mirror of
https://fastgit.cc/https://github.com/anomalyco/opencode
synced 2026-05-01 22:44:21 +08:00
Compare commits
557 Commits
kit/fs-cli
...
shell-test
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99660c90eb | ||
|
|
7a02eee0f4 | ||
|
|
cf45a8d807 | ||
|
|
435becbea0 | ||
|
|
0405bc74e9 | ||
|
|
4dab2a8555 | ||
|
|
3776d85e15 | ||
|
|
d01ad4c499 | ||
|
|
28025a0f36 | ||
|
|
1220f784fe | ||
|
|
28f7d31e72 | ||
|
|
66936b0fff | ||
|
|
3a5507de95 | ||
|
|
86715fecc4 | ||
|
|
3062d3e070 | ||
|
|
d89bfc32ac | ||
|
|
011c23761b | ||
|
|
a8c8d2dd79 | ||
|
|
9f7ecd65e5 | ||
|
|
f8e939d96f | ||
|
|
923af96d26 | ||
|
|
a882e958b3 | ||
|
|
2cda629c8d | ||
|
|
f033d2d8fb | ||
|
|
a4bd88ab97 | ||
|
|
f4616c8268 | ||
|
|
4712f0f3c1 | ||
|
|
6c1268f3b1 | ||
|
|
2e156b8990 | ||
|
|
3bfe6a1ef6 | ||
|
|
5c5069b622 | ||
|
|
f8c6ddd4cb | ||
|
|
e50a688ca3 | ||
|
|
334ab4707c | ||
|
|
87321942fe | ||
|
|
a771859362 | ||
|
|
31d01d404a | ||
|
|
814e83ffec | ||
|
|
4c3e65c877 | ||
|
|
98ea5b6e7e | ||
|
|
3f8c659056 | ||
|
|
3910a6e527 | ||
|
|
24892559ae | ||
|
|
cd93533b1f | ||
|
|
0590452456 | ||
|
|
93940a1859 | ||
|
|
1e439b8226 | ||
|
|
8b2f8355b2 | ||
|
|
aed03078f8 | ||
|
|
c50d65b4d6 | ||
|
|
353532b1c1 | ||
|
|
9df7c78ebe | ||
|
|
eb7555d3c6 | ||
|
|
2cd89d64e9 | ||
|
|
0517ab4695 | ||
|
|
bbf67d0fff | ||
|
|
38deb0f3ee | ||
|
|
9b6db08d21 | ||
|
|
3ae74cb047 | ||
|
|
6002500bc0 | ||
|
|
785f3589ab | ||
|
|
a419f1c50f | ||
|
|
871789ce64 | ||
|
|
df27baa00d | ||
|
|
9730008543 | ||
|
|
ac26394fcb | ||
|
|
6387b35a2d | ||
|
|
1cd4c92242 | ||
|
|
e383df4b17 | ||
|
|
58db41b4b9 | ||
|
|
5d133f2785 | ||
|
|
e9b1d3b940 | ||
|
|
3a082a0efd | ||
|
|
504fd1b373 | ||
|
|
574b2c2170 | ||
|
|
fa8b7bc4d2 | ||
|
|
6196b81e0a | ||
|
|
d884ab73d5 | ||
|
|
71d196d3cd | ||
|
|
20756e0ee4 | ||
|
|
894e638914 | ||
|
|
8113a4360e | ||
|
|
c819804638 | ||
|
|
06066dbb7b | ||
|
|
69b8ea0d66 | ||
|
|
b0455583aa | ||
|
|
ed802fd121 | ||
|
|
1593c3ed16 | ||
|
|
e89543811c | ||
|
|
1a76799fd8 | ||
|
|
fa623964a2 | ||
|
|
628102ad04 | ||
|
|
ad7ae7353f | ||
|
|
8043cfa68d | ||
|
|
d2181e9273 | ||
|
|
5e9fb3cc90 | ||
|
|
2da6d860e0 | ||
|
|
df0c1f649c | ||
|
|
d6dea3f3e0 | ||
|
|
0bcf734a67 | ||
|
|
b1c3095edd | ||
|
|
b0f565b74a | ||
|
|
2ae64f426b | ||
|
|
7933657135 | ||
|
|
caaddf0964 | ||
|
|
1a20703469 | ||
|
|
8751f48a75 | ||
|
|
58232d896e | ||
|
|
cd6415f332 | ||
|
|
c9fb8d0ce7 | ||
|
|
1e1a500603 | ||
|
|
ecc06a3d8f | ||
|
|
3205f122eb | ||
|
|
e95474df05 | ||
|
|
96a534d8c6 | ||
|
|
9579429276 | ||
|
|
2486621ca1 | ||
|
|
b5acc2203c | ||
|
|
8cc2c81d57 | ||
|
|
8d2d12d9c6 | ||
|
|
811a7e9a8b | ||
|
|
febadc5589 | ||
|
|
92c005866b | ||
|
|
224548d87d | ||
|
|
8a7bb7c6a9 | ||
|
|
22d33c57af | ||
|
|
1e0137f624 | ||
|
|
38e2f4cdda | ||
|
|
bd54b68c12 | ||
|
|
a08aa21cb3 | ||
|
|
eb9906420f | ||
|
|
4964ce480c | ||
|
|
e5687d646c | ||
|
|
a38d53fe2f | ||
|
|
6278ce51ce | ||
|
|
53b0084ce2 | ||
|
|
f74a255ca9 | ||
|
|
3e8abac625 | ||
|
|
65e99fcc2e | ||
|
|
bad025eba9 | ||
|
|
06dde3afd3 | ||
|
|
ad65af28e7 | ||
|
|
bd1bdc4f04 | ||
|
|
debcff2b6b | ||
|
|
8b3323708d | ||
|
|
3406f18746 | ||
|
|
7e576eea41 | ||
|
|
d68ebee555 | ||
|
|
ae7a3518f7 | ||
|
|
16caaa2229 | ||
|
|
91468fe455 | ||
|
|
7c6948cf6f | ||
|
|
7a568a457f | ||
|
|
3ddc69ec2b | ||
|
|
f3d5a71620 | ||
|
|
c6c56ac2cf | ||
|
|
e539efe2b9 | ||
|
|
687b758882 | ||
|
|
84e322b0fd | ||
|
|
8bc4f91fd9 | ||
|
|
93e633fb7d | ||
|
|
cbe702c09d | ||
|
|
a7a85c94b8 | ||
|
|
6e0178655b | ||
|
|
e4be557928 | ||
|
|
b9640fc7e4 | ||
|
|
29f05cb1ee | ||
|
|
48acab48ad | ||
|
|
5ae74aa881 | ||
|
|
6eddf08244 | ||
|
|
9c7e52b8a1 | ||
|
|
a824064c4c | ||
|
|
33b2795cc8 | ||
|
|
10bd044c55 | ||
|
|
c09bcfe531 | ||
|
|
83227be0ca | ||
|
|
8ee47a0533 | ||
|
|
a546e88f37 | ||
|
|
e998c9e9cb | ||
|
|
889087c966 | ||
|
|
7f3b64c7c4 | ||
|
|
e60a6e3a82 | ||
|
|
135c8f0e99 | ||
|
|
f02504bb80 | ||
|
|
40834fdf2f | ||
|
|
fc0588954b | ||
|
|
75960e3bf3 | ||
|
|
f14ac472a3 | ||
|
|
9ed93715ef | ||
|
|
b34ca44abe | ||
|
|
40ba8f3570 | ||
|
|
e543acf923 | ||
|
|
d183568644 | ||
|
|
f27eb8f09e | ||
|
|
ad0545335a | ||
|
|
cfbbae7323 | ||
|
|
940f971ca0 | ||
|
|
78ca49a1bc | ||
|
|
1d54b0e540 | ||
|
|
7e971d8302 | ||
|
|
54b3b3fe05 | ||
|
|
9d012b0621 | ||
|
|
fbb0a93e12 | ||
|
|
e2e7a8d722 | ||
|
|
ce7923adaf | ||
|
|
a26d53151b | ||
|
|
5eaef6b758 | ||
|
|
c5c38cad9c | ||
|
|
9918f389e7 | ||
|
|
dd8c424806 | ||
|
|
078d8a07cf | ||
|
|
1ee712e549 | ||
|
|
55315bdffa | ||
|
|
882b8e1e75 | ||
|
|
95edbc0ae6 | ||
|
|
11cd4fb639 | ||
|
|
9c16bd1e30 | ||
|
|
5e9d5c734e | ||
|
|
b382d1a467 | ||
|
|
23f31475e7 | ||
|
|
c0eab9e442 | ||
|
|
8a1e85d0c8 | ||
|
|
2793502db2 | ||
|
|
9f7bd0246c | ||
|
|
a6a4350d10 | ||
|
|
471b9f4dc4 | ||
|
|
24fb9b1296 | ||
|
|
3573019916 | ||
|
|
fc5b353144 | ||
|
|
1dd257b76a | ||
|
|
5fa1673341 | ||
|
|
daaa1c7e26 | ||
|
|
1fae784b81 | ||
|
|
81b7b58a5e | ||
|
|
866188a643 | ||
|
|
e6fd57165e | ||
|
|
a5d99e7a3c | ||
|
|
a92c75e5f4 | ||
|
|
826fd3350c | ||
|
|
23a2d01282 | ||
|
|
5181f9b4e1 | ||
|
|
f52ae28432 | ||
|
|
36119ff173 | ||
|
|
bb90f3bbf9 | ||
|
|
05cdb7c107 | ||
|
|
b493dabfe6 | ||
|
|
c4816f944e | ||
|
|
211136e3a8 | ||
|
|
cf0a53c501 | ||
|
|
2899984819 | ||
|
|
eafbe5c57c | ||
|
|
7b98f544ff | ||
|
|
b5aba5807c | ||
|
|
d5c4c26b4b | ||
|
|
a35b8a95c2 | ||
|
|
cded68a2e2 | ||
|
|
0068ccec35 | ||
|
|
89e8994fd1 | ||
|
|
5980b0a5ee | ||
|
|
89029a20ef | ||
|
|
ce69bd97b9 | ||
|
|
999d8651aa | ||
|
|
ed0f022502 | ||
|
|
b1307d5c2a | ||
|
|
dc16013b4f | ||
|
|
e7686dbd64 | ||
|
|
47f553f9ba | ||
|
|
d11268ece7 | ||
|
|
650a13a690 | ||
|
|
54435325b6 | ||
|
|
11fa257549 | ||
|
|
6af8ab0df2 | ||
|
|
984f5ed6eb | ||
|
|
c2061c6bbf | ||
|
|
b708e8431e | ||
|
|
9b6c397171 | ||
|
|
9b0659d4f9 | ||
|
|
f83cecaaf6 | ||
|
|
aa05b9abe5 | ||
|
|
68834cfcc3 | ||
|
|
5621373bc2 | ||
|
|
88582566bf | ||
|
|
d6e1362fee | ||
|
|
b275b8580d | ||
|
|
467be08e67 | ||
|
|
bbb422d125 | ||
|
|
b1f076558c | ||
|
|
992435aaf8 | ||
|
|
2f73e73e9d | ||
|
|
4c30a78cd9 | ||
|
|
a8c78fc005 | ||
|
|
fcb473ff64 | ||
|
|
797953c88d | ||
|
|
ce0cfb0ea5 | ||
|
|
13dfe569ef | ||
|
|
c491161c0c | ||
|
|
fde3d9133b | ||
|
|
0d582f9d3f | ||
|
|
1a59133168 | ||
|
|
803d9eb7ad | ||
|
|
a27d3c1623 | ||
|
|
551216a452 | ||
|
|
38cd3979f2 | ||
|
|
3fe602cda3 | ||
|
|
3a4b49095c | ||
|
|
ac5b395c5d | ||
|
|
8fbbca5f4b | ||
|
|
2415820ecd | ||
|
|
20103eb97b | ||
|
|
10c4ab9a3d | ||
|
|
7e39c9b950 | ||
|
|
cc063d4c32 | ||
|
|
3707e4a49c | ||
|
|
cb425ac927 | ||
|
|
0f80c827ed | ||
|
|
fffc496f41 | ||
|
|
06ae43920b | ||
|
|
e78d75a003 | ||
|
|
ec3ac0c4b0 | ||
|
|
c57c5315c1 | ||
|
|
a726530735 | ||
|
|
d9950598d0 | ||
|
|
81f0885879 | ||
|
|
65b2a10e97 | ||
|
|
7605acff65 | ||
|
|
e7f8f7fa3b | ||
|
|
72d7cb717d | ||
|
|
f0caeb9b25 | ||
|
|
76a141090e | ||
|
|
4bd5a158a5 | ||
|
|
dfaae14544 | ||
|
|
79e9baf55a | ||
|
|
a4882290aa | ||
|
|
9ee89f7868 | ||
|
|
67dbb3cf18 | ||
|
|
4260c40efa | ||
|
|
0bedea52b1 | ||
|
|
fbbab9d6c8 | ||
|
|
cccb907a9b | ||
|
|
ee7339f2c6 | ||
|
|
c51f3e35ca | ||
|
|
7b3bb9a761 | ||
|
|
dc38f22bd8 | ||
|
|
220e3e9a2b | ||
|
|
f135c0b5ee | ||
|
|
ebe6ea580d | ||
|
|
ee708040f6 | ||
|
|
61c4815a37 | ||
|
|
01bb54a94d | ||
|
|
f592c3846b | ||
|
|
c026e25088 | ||
|
|
8ba73bed23 | ||
|
|
4f8986aa48 | ||
|
|
9c87a144e8 | ||
|
|
5b9fa32255 | ||
|
|
f13778215a | ||
|
|
326471a25c | ||
|
|
6405e3a7b1 | ||
|
|
8afb625bab | ||
|
|
c59df636cc | ||
|
|
94878d76f8 | ||
|
|
5022895e2b | ||
|
|
54046e0b98 | ||
|
|
d2cb1613ac | ||
|
|
266fb93422 | ||
|
|
51d8219c46 | ||
|
|
d6af5a686c | ||
|
|
39342b0e75 | ||
|
|
54078c4cae | ||
|
|
c0bfccc15e | ||
|
|
53dc7b1649 | ||
|
|
635970b0a1 | ||
|
|
059b32c212 | ||
|
|
2704ad9110 | ||
|
|
06d247c709 | ||
|
|
974fa1b8b1 | ||
|
|
fb02744460 | ||
|
|
79732ab175 | ||
|
|
f6dbb2f3e0 | ||
|
|
fdd5b77bfd | ||
|
|
cde105e7a8 | ||
|
|
1291e82bb4 | ||
|
|
19d15d9ff7 | ||
|
|
4e27804160 | ||
|
|
bae80af1b4 | ||
|
|
f9aa3d77cd | ||
|
|
5d47ea0918 | ||
|
|
c03fa36257 | ||
|
|
1089fa0415 | ||
|
|
715786bbf9 | ||
|
|
218eca7c2b | ||
|
|
30fc791480 | ||
|
|
e2d161dfdd | ||
|
|
23d48a7cf1 | ||
|
|
cb18f2ef40 | ||
|
|
dbe2ff52b2 | ||
|
|
9db40996cc | ||
|
|
9f201d6370 | ||
|
|
0e86466f99 | ||
|
|
32548bcb4a | ||
|
|
86c54c5acc | ||
|
|
ae584332b3 | ||
|
|
1694c5bfe1 | ||
|
|
cdfbb26c00 | ||
|
|
610c036ef1 | ||
|
|
2638e2acfa | ||
|
|
49bbea5aed | ||
|
|
5fccdc9fc7 | ||
|
|
664b2c36e8 | ||
|
|
964474a1b1 | ||
|
|
ab15fc1575 | ||
|
|
99d392a4fb | ||
|
|
ae9a696607 | ||
|
|
bd51a0d35b | ||
|
|
8c191b10c2 | ||
|
|
cb6a9253fe | ||
|
|
23f97ac49d | ||
|
|
021ab50fb1 | ||
|
|
3fe906f517 | ||
|
|
a8d8a35cd3 | ||
|
|
9b77430d0d | ||
|
|
1045a43603 | ||
|
|
26af77cd1e | ||
|
|
25a9de301a | ||
|
|
e0d71f124e | ||
|
|
1c33b866ba | ||
|
|
5e650fd9e2 | ||
|
|
76275fc3ab | ||
|
|
6c3b28db64 | ||
|
|
2fe9d94470 | ||
|
|
219b473e66 | ||
|
|
7c1b30291c | ||
|
|
47e0e2342c | ||
|
|
bf4c107829 | ||
|
|
9afbdc102c | ||
|
|
370770122c | ||
|
|
143817d44e | ||
|
|
c60862fc9e | ||
|
|
bee5f919fc | ||
|
|
cefa7f04c6 | ||
|
|
03e20e6ac1 | ||
|
|
c5deeee8c7 | ||
|
|
8b1f0e2d90 | ||
|
|
9bf2dfea35 | ||
|
|
33bb847a1d | ||
|
|
bfffc3c2c6 | ||
|
|
b28956f0db | ||
|
|
d82bc3a421 | ||
|
|
06afd33291 | ||
|
|
305460b25f | ||
|
|
8c0205a84a | ||
|
|
378c05f202 | ||
|
|
cc7acd90ab | ||
|
|
a200f6fb8b | ||
|
|
2b1696f1d1 | ||
|
|
8ab17f5ce0 | ||
|
|
6ce481e95b | ||
|
|
42771c1db3 | ||
|
|
2e18a603f0 | ||
|
|
7341718f92 | ||
|
|
ef90b93205 | ||
|
|
3f7df08be9 | ||
|
|
ef6c26c730 | ||
|
|
8b3b608ba9 | ||
|
|
97918500d4 | ||
|
|
e2c0803962 | ||
|
|
f418fd5632 | ||
|
|
675a46e23e | ||
|
|
150ab07a83 | ||
|
|
6b20838981 | ||
|
|
c8af8f96ce | ||
|
|
5011465c81 | ||
|
|
f6cc228684 | ||
|
|
9f4b73b6a3 | ||
|
|
bd29004831 | ||
|
|
8aa0f9fe95 | ||
|
|
c802695ee9 | ||
|
|
225a769411 | ||
|
|
0e20382396 | ||
|
|
509bc11f81 | ||
|
|
f24207844f | ||
|
|
1ca257e356 | ||
|
|
d4cfbd020d | ||
|
|
581d5208ca | ||
|
|
a427a28fa9 | ||
|
|
0beaf04df5 | ||
|
|
80f1f1b5b8 | ||
|
|
343a564183 | ||
|
|
b0eae5e12f | ||
|
|
702f741267 | ||
|
|
665a843086 | ||
|
|
1508196c0f | ||
|
|
f6243603f8 | ||
|
|
379e40d772 | ||
|
|
6c7e9f6f3a | ||
|
|
48f88af9aa | ||
|
|
60c927cf4f | ||
|
|
069cef8a44 | ||
|
|
cf423d2769 | ||
|
|
62ddb9d3ad | ||
|
|
0b975b01fb | ||
|
|
bb90aa6cb2 | ||
|
|
ce4e47a2e3 | ||
|
|
e3677c2ba2 | ||
|
|
a653a4b887 | ||
|
|
f7edffc11a | ||
|
|
dc16488bd7 | ||
|
|
d7a072dd46 | ||
|
|
5ae91aa810 | ||
|
|
18538e359b | ||
|
|
47577ae857 | ||
|
|
d22b5f026d | ||
|
|
26cdbc20b2 | ||
|
|
360d8dd940 | ||
|
|
426815a829 | ||
|
|
c6286d1bb9 | ||
|
|
710c81984a | ||
|
|
a1dbfb5967 | ||
|
|
64cc4623b5 | ||
|
|
5eae926846 | ||
|
|
cce05c1665 | ||
|
|
34213d4446 | ||
|
|
70aeebf2df | ||
|
|
d6b14e2467 | ||
|
|
6625766350 | ||
|
|
7baf998752 | ||
|
|
1d81335ab5 | ||
|
|
f7d4665e40 | ||
|
|
bbdbc107ae | ||
|
|
0fb0135e51 | ||
|
|
02f2cf439e | ||
|
|
6d42f97644 | ||
|
|
307251bf3c | ||
|
|
074ef032ee | ||
|
|
4ca809ef4e | ||
|
|
a147ad68e6 | ||
|
|
ac2fa668cf | ||
|
|
3d6f90cb53 | ||
|
|
a554fad232 | ||
|
|
4dd0d1f67e | ||
|
|
672ee28635 | ||
|
|
e16589f8b5 | ||
|
|
83e257b468 | ||
|
|
916131be19 | ||
|
|
d2ea6700aa | ||
|
|
6bed7d469d | ||
|
|
3b75f16119 | ||
|
|
250e30bc7d | ||
|
|
e83b22159d | ||
|
|
348a84969d | ||
|
|
8ba4799b3e | ||
|
|
9640d889ba | ||
|
|
4ae7c77f8a | ||
|
|
f1751401aa | ||
|
|
9819eb0461 | ||
|
|
aa86fb75ad | ||
|
|
6f5a3d30fd |
1
.github/TEAM_MEMBERS
vendored
1
.github/TEAM_MEMBERS
vendored
@@ -13,3 +13,4 @@ R44VC0RP
|
||||
rekram1-node
|
||||
RhysSullivan
|
||||
thdxr
|
||||
simonklee
|
||||
|
||||
1
.github/VOUCHED.td
vendored
1
.github/VOUCHED.td
vendored
@@ -27,6 +27,7 @@ r44vc0rp
|
||||
rekram1-node
|
||||
-ricardo-m-l
|
||||
-robinmordasiewicz
|
||||
rubdos
|
||||
shantur
|
||||
simonklee
|
||||
-spider-yamet clawdbot/llm psychosis, spam pinging the team
|
||||
|
||||
9
.github/actions/setup-bun/action.yml
vendored
9
.github/actions/setup-bun/action.yml
vendored
@@ -1,5 +1,10 @@
|
||||
name: "Setup Bun"
|
||||
description: "Setup Bun with caching and install dependencies"
|
||||
inputs:
|
||||
install-flags:
|
||||
description: "Additional flags to pass to 'bun install'"
|
||||
required: false
|
||||
default: ""
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
@@ -46,8 +51,8 @@ runs:
|
||||
# e.g. ./patches/ for standard-openapi
|
||||
# https://github.com/oven-sh/bun/issues/28147
|
||||
if [ "$RUNNER_OS" = "Windows" ]; then
|
||||
bun install --linker hoisted
|
||||
bun install --linker hoisted ${{ inputs.install-flags }}
|
||||
else
|
||||
bun install
|
||||
bun install ${{ inputs.install-flags }}
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
8
.github/workflows/publish.yml
vendored
8
.github/workflows/publish.yml
vendored
@@ -402,12 +402,14 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
settings:
|
||||
- host: macos-latest
|
||||
- host: macos-26-intel
|
||||
target: x86_64-apple-darwin
|
||||
platform_flag: --mac --x64
|
||||
- host: macos-latest
|
||||
bun_install_flags: --os=darwin --cpu=x64
|
||||
- host: macos-26
|
||||
target: aarch64-apple-darwin
|
||||
platform_flag: --mac --arm64
|
||||
bun_install_flags: --os=darwin --cpu=arm64
|
||||
# github-hosted: blacksmith lacks ARM64 MSVC cross-compilation toolchain
|
||||
- host: "windows-2025"
|
||||
target: aarch64-pc-windows-msvc
|
||||
@@ -437,6 +439,8 @@ jobs:
|
||||
run: echo "${{ secrets.APPLE_API_KEY_PATH }}" > $RUNNER_TEMP/apple-api-key.p8
|
||||
|
||||
- uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
install-flags: ${{ matrix.settings.bun_install_flags }}
|
||||
|
||||
- name: Azure login
|
||||
if: runner.os == 'Windows'
|
||||
|
||||
@@ -594,7 +594,6 @@ OPENCODE_DISABLE_CLAUDE_CODE
|
||||
OPENCODE_DISABLE_CLAUDE_CODE_PROMPT
|
||||
OPENCODE_DISABLE_CLAUDE_CODE_SKILLS
|
||||
OPENCODE_DISABLE_DEFAULT_PLUGINS
|
||||
OPENCODE_DISABLE_FILETIME_CHECK
|
||||
OPENCODE_DISABLE_LSP_DOWNLOAD
|
||||
OPENCODE_DISABLE_MODELS_FETCH
|
||||
OPENCODE_DISABLE_PRUNE
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"provider": {
|
||||
"opencode": {
|
||||
"options": {},
|
||||
},
|
||||
},
|
||||
"provider": {},
|
||||
"permission": {
|
||||
"edit": {
|
||||
"packages/opencode/migration/*": "deny",
|
||||
|
||||
@@ -7,7 +7,7 @@ async function githubFetch(endpoint: string, options: RequestInit = {}) {
|
||||
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
|
||||
Accept: "application/vnd.github+json",
|
||||
"Content-Type": "application/json",
|
||||
...options.headers,
|
||||
...(options.headers instanceof Headers ? Object.fromEntries(options.headers.entries()) : options.headers),
|
||||
},
|
||||
})
|
||||
if (!response.ok) {
|
||||
|
||||
@@ -28,7 +28,7 @@ async function githubFetch(endpoint: string, options: RequestInit = {}) {
|
||||
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
|
||||
Accept: "application/vnd.github+json",
|
||||
"Content-Type": "application/json",
|
||||
...options.headers,
|
||||
...(options.headers instanceof Headers ? Object.fromEntries(options.headers.entries()) : options.headers),
|
||||
},
|
||||
})
|
||||
if (!response.ok) {
|
||||
|
||||
51
.oxlintrc.json
Normal file
51
.oxlintrc.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/oxc-project.github.io/refs/heads/json-schema/src/public/.oxlintrc.schema.json",
|
||||
"options": {
|
||||
"typeAware": true
|
||||
},
|
||||
"categories": {
|
||||
"suspicious": "warn"
|
||||
},
|
||||
"rules": {
|
||||
"typescript/no-base-to-string": "warn",
|
||||
// Effect uses `function*` with Effect.gen/Effect.fnUntraced that don't always yield
|
||||
"require-yield": "off",
|
||||
// SolidJS uses `let ref: T | undefined` for JSX ref bindings assigned at runtime
|
||||
"no-unassigned-vars": "off",
|
||||
// SolidJS tracks reactive deps by reading properties inside createEffect
|
||||
"no-unused-expressions": "off",
|
||||
// Intentional control char matching (ANSI escapes, null byte sanitization)
|
||||
"no-control-regex": "off",
|
||||
// SST and plugin tools require triple-slash references
|
||||
"triple-slash-reference": "off",
|
||||
|
||||
// Suspicious category: suppress noisy rules
|
||||
// Effect's nested function* closures inherently shadow outer scope
|
||||
"no-shadow": "off",
|
||||
// Namespace-heavy codebase makes this too noisy
|
||||
"unicorn/consistent-function-scoping": "off",
|
||||
// Opinionated — .sort()/.reverse() mutation is fine in this codebase
|
||||
"unicorn/no-array-sort": "off",
|
||||
"unicorn/no-array-reverse": "off",
|
||||
// Not relevant — this isn't a DOM event handler codebase
|
||||
"unicorn/prefer-add-event-listener": "off",
|
||||
// Bundler handles module resolution
|
||||
"unicorn/require-module-specifiers": "off",
|
||||
// postMessage target origin not relevant for this codebase
|
||||
"unicorn/require-post-message-target-origin": "off",
|
||||
// Side-effectful constructors are intentional in some places
|
||||
"no-new": "off",
|
||||
|
||||
// Type-aware: catch unhandled promises
|
||||
"typescript/no-floating-promises": "warn",
|
||||
// Warn when spreading non-plain objects (Headers, class instances, etc.)
|
||||
"typescript/no-misused-spread": "warn"
|
||||
},
|
||||
"options": {
|
||||
"typeAware": true
|
||||
},
|
||||
"options": {
|
||||
"typeAware": true
|
||||
},
|
||||
"ignorePatterns": ["**/node_modules", "**/dist", "**/.build", "**/.sst", "**/*.d.ts", "**/sdk.gen.ts"]
|
||||
}
|
||||
27
AGENTS.md
27
AGENTS.md
@@ -11,35 +11,10 @@
|
||||
- Keep things in one function unless composable or reusable
|
||||
- Avoid `try`/`catch` where possible
|
||||
- Avoid using the `any` type
|
||||
- Prefer single word variable names where possible
|
||||
- Use Bun APIs when possible, like `Bun.file()`
|
||||
- Rely on type inference when possible; avoid explicit type annotations or interfaces unless necessary for exports or clarity
|
||||
- Prefer functional array methods (flatMap, filter, map) over for loops; use type guards on filter to maintain type inference downstream
|
||||
|
||||
### Naming
|
||||
|
||||
Prefer single word names for variables and functions. Only use multiple words if necessary.
|
||||
|
||||
### Naming Enforcement (Read This)
|
||||
|
||||
THIS RULE IS MANDATORY FOR AGENT WRITTEN CODE.
|
||||
|
||||
- Use single word names by default for new locals, params, and helper functions.
|
||||
- Multi-word names are allowed only when a single word would be unclear or ambiguous.
|
||||
- Do not introduce new camelCase compounds when a short single-word alternative is clear.
|
||||
- Before finishing edits, review touched lines and shorten newly introduced identifiers where possible.
|
||||
- Good short names to prefer: `pid`, `cfg`, `err`, `opts`, `dir`, `root`, `child`, `state`, `timeout`.
|
||||
- Examples to avoid unless truly required: `inputPID`, `existingClient`, `connectTimeout`, `workerPath`.
|
||||
|
||||
```ts
|
||||
// Good
|
||||
const foo = 1
|
||||
function journal(dir: string) {}
|
||||
|
||||
// Bad
|
||||
const fooBar = 1
|
||||
function prepareJournal(dir: string) {}
|
||||
```
|
||||
- In `src/config`, follow the existing self-export pattern at the top of the file (for example `export * as ConfigAgent from "./agent"`) when adding a new config module.
|
||||
|
||||
Reduce total variable count by inlining when a value is only used once.
|
||||
|
||||
|
||||
210
bun.lock
210
bun.lock
@@ -19,6 +19,8 @@
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"glob": "13.0.5",
|
||||
"husky": "9.1.7",
|
||||
"oxlint": "1.60.0",
|
||||
"oxlint-tsgolint": "0.21.0",
|
||||
"prettier": "3.6.2",
|
||||
"semver": "^7.6.0",
|
||||
"sst": "3.18.10",
|
||||
@@ -27,7 +29,7 @@
|
||||
},
|
||||
"packages/app": {
|
||||
"name": "@opencode-ai/app",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
@@ -81,7 +83,7 @@
|
||||
},
|
||||
"packages/console/app": {
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"dependencies": {
|
||||
"@cloudflare/vite-plugin": "1.15.2",
|
||||
"@ibm/plex": "6.4.1",
|
||||
@@ -115,7 +117,7 @@
|
||||
},
|
||||
"packages/console/core": {
|
||||
"name": "@opencode-ai/console-core",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-sts": "3.782.0",
|
||||
"@jsx-email/render": "1.1.1",
|
||||
@@ -142,7 +144,7 @@
|
||||
},
|
||||
"packages/console/function": {
|
||||
"name": "@opencode-ai/console-function",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "3.0.64",
|
||||
"@ai-sdk/openai": "3.0.48",
|
||||
@@ -166,7 +168,7 @@
|
||||
},
|
||||
"packages/console/mail": {
|
||||
"name": "@opencode-ai/console-mail",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"dependencies": {
|
||||
"@jsx-email/all": "2.2.3",
|
||||
"@jsx-email/cli": "1.4.3",
|
||||
@@ -190,7 +192,7 @@
|
||||
},
|
||||
"packages/desktop": {
|
||||
"name": "@opencode-ai/desktop",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"dependencies": {
|
||||
"@opencode-ai/app": "workspace:*",
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
@@ -223,8 +225,9 @@
|
||||
},
|
||||
"packages/desktop-electron": {
|
||||
"name": "@opencode-ai/desktop-electron",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"dependencies": {
|
||||
"drizzle-orm": "catalog:",
|
||||
"effect": "catalog:",
|
||||
"electron-context-menu": "4.1.2",
|
||||
"electron-log": "^5",
|
||||
@@ -246,7 +249,7 @@
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"@valibot/to-json-schema": "1.6.0",
|
||||
"electron": "40.4.1",
|
||||
"electron": "41.2.1",
|
||||
"electron-builder": "^26",
|
||||
"electron-vite": "^5",
|
||||
"solid-js": "catalog:",
|
||||
@@ -266,7 +269,7 @@
|
||||
},
|
||||
"packages/enterprise": {
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"dependencies": {
|
||||
"@opencode-ai/shared": "workspace:*",
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
@@ -295,7 +298,7 @@
|
||||
},
|
||||
"packages/function": {
|
||||
"name": "@opencode-ai/function",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"dependencies": {
|
||||
"@octokit/auth-app": "8.0.1",
|
||||
"@octokit/rest": "catalog:",
|
||||
@@ -311,7 +314,7 @@
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "opencode",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -320,15 +323,15 @@
|
||||
"@actions/github": "6.0.1",
|
||||
"@agentclientprotocol/sdk": "0.16.1",
|
||||
"@ai-sdk/alibaba": "1.0.17",
|
||||
"@ai-sdk/amazon-bedrock": "4.0.93",
|
||||
"@ai-sdk/anthropic": "3.0.67",
|
||||
"@ai-sdk/amazon-bedrock": "4.0.96",
|
||||
"@ai-sdk/anthropic": "3.0.71",
|
||||
"@ai-sdk/azure": "3.0.49",
|
||||
"@ai-sdk/cerebras": "2.0.41",
|
||||
"@ai-sdk/cohere": "3.0.27",
|
||||
"@ai-sdk/deepinfra": "2.0.41",
|
||||
"@ai-sdk/gateway": "3.0.97",
|
||||
"@ai-sdk/gateway": "3.0.104",
|
||||
"@ai-sdk/google": "3.0.63",
|
||||
"@ai-sdk/google-vertex": "4.0.109",
|
||||
"@ai-sdk/google-vertex": "4.0.112",
|
||||
"@ai-sdk/groq": "3.0.31",
|
||||
"@ai-sdk/mistral": "3.0.27",
|
||||
"@ai-sdk/openai": "3.0.53",
|
||||
@@ -351,19 +354,21 @@
|
||||
"@lydell/node-pty": "catalog:",
|
||||
"@modelcontextprotocol/sdk": "1.27.1",
|
||||
"@npmcli/arborist": "9.4.0",
|
||||
"@npmcli/config": "10.8.1",
|
||||
"@octokit/graphql": "9.0.2",
|
||||
"@octokit/rest": "catalog:",
|
||||
"@openauthjs/openauth": "catalog:",
|
||||
"@opencode-ai/plugin": "workspace:*",
|
||||
"@opencode-ai/script": "workspace:*",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@opencode-ai/server": "workspace:*",
|
||||
"@openrouter/ai-sdk-provider": "2.5.1",
|
||||
"@opentelemetry/api": "1.9.0",
|
||||
"@opentelemetry/context-async-hooks": "2.6.1",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "0.214.0",
|
||||
"@opentelemetry/sdk-trace-base": "2.6.1",
|
||||
"@opentelemetry/sdk-trace-node": "2.6.1",
|
||||
"@opentui/core": "0.1.99",
|
||||
"@opentui/solid": "0.1.99",
|
||||
"@opentui/core": "0.1.103",
|
||||
"@opentui/solid": "0.1.103",
|
||||
"@parcel/watcher": "2.5.1",
|
||||
"@pierre/diffs": "catalog:",
|
||||
"@solid-primitives/event-bus": "1.1.2",
|
||||
@@ -383,7 +388,7 @@
|
||||
"drizzle-orm": "catalog:",
|
||||
"effect": "catalog:",
|
||||
"fuzzysort": "3.1.0",
|
||||
"gitlab-ai-provider": "6.4.2",
|
||||
"gitlab-ai-provider": "6.6.0",
|
||||
"glob": "13.0.5",
|
||||
"google-auth-library": "10.5.0",
|
||||
"gray-matter": "4.0.3",
|
||||
@@ -401,7 +406,6 @@
|
||||
"opentui-spinner": "0.0.6",
|
||||
"partial-json": "0.1.7",
|
||||
"remeda": "catalog:",
|
||||
"ripgrep": "0.3.1",
|
||||
"semver": "^7.6.3",
|
||||
"solid-js": "catalog:",
|
||||
"strip-ansi": "7.1.2",
|
||||
@@ -455,23 +459,23 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"effect": "catalog:",
|
||||
"zod": "catalog:",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@opentui/core": "0.1.99",
|
||||
"@opentui/solid": "0.1.99",
|
||||
"@opentui/core": "0.1.103",
|
||||
"@opentui/solid": "0.1.103",
|
||||
"@tsconfig/node22": "catalog:",
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentui/core": ">=0.1.99",
|
||||
"@opentui/solid": ">=0.1.99",
|
||||
"@opentui/core": ">=0.1.103",
|
||||
"@opentui/solid": ">=0.1.103",
|
||||
},
|
||||
"optionalPeers": [
|
||||
"@opentui/core",
|
||||
@@ -490,7 +494,7 @@
|
||||
},
|
||||
"packages/sdk/js": {
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"dependencies": {
|
||||
"cross-spawn": "catalog:",
|
||||
},
|
||||
@@ -503,19 +507,9 @@
|
||||
"typescript": "catalog:",
|
||||
},
|
||||
},
|
||||
"packages/server": {
|
||||
"name": "@opencode-ai/server",
|
||||
"version": "1.4.6",
|
||||
"dependencies": {
|
||||
"effect": "catalog:",
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "catalog:",
|
||||
},
|
||||
},
|
||||
"packages/shared": {
|
||||
"name": "@opencode-ai/shared",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -523,18 +517,23 @@
|
||||
"@effect/platform-node": "catalog:",
|
||||
"@npmcli/arborist": "catalog:",
|
||||
"effect": "catalog:",
|
||||
"glob": "13.0.5",
|
||||
"mime-types": "3.0.2",
|
||||
"minimatch": "10.2.5",
|
||||
"semver": "catalog:",
|
||||
"xdg-basedir": "5.1.0",
|
||||
"zod": "catalog:",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/bun": "catalog:",
|
||||
"@types/bun": "catalog:",
|
||||
"@types/npmcli__arborist": "6.3.3",
|
||||
"@types/semver": "catalog:",
|
||||
},
|
||||
},
|
||||
"packages/slack": {
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@slack/bolt": "^3.17.1",
|
||||
@@ -569,7 +568,7 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
@@ -618,7 +617,7 @@
|
||||
},
|
||||
"packages/web": {
|
||||
"name": "@opencode-ai/web",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "12.6.3",
|
||||
"@astrojs/markdown-remark": "6.3.1",
|
||||
@@ -662,6 +661,7 @@
|
||||
"patchedDependencies": {
|
||||
"solid-js@1.9.10": "patches/solid-js@1.9.10.patch",
|
||||
"@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch",
|
||||
"@npmcli/agent@4.0.0": "patches/@npmcli%2Fagent@4.0.0.patch",
|
||||
},
|
||||
"overrides": {
|
||||
"@types/bun": "catalog:",
|
||||
@@ -677,6 +677,8 @@
|
||||
"@npmcli/arborist": "9.4.0",
|
||||
"@octokit/rest": "22.0.0",
|
||||
"@openauthjs/openauth": "0.0.0-20250322224806",
|
||||
"@opentui/core": "0.1.99",
|
||||
"@opentui/solid": "0.1.99",
|
||||
"@pierre/diffs": "1.1.0-beta.18",
|
||||
"@playwright/test": "1.59.1",
|
||||
"@solid-primitives/storage": "4.3.3",
|
||||
@@ -686,13 +688,13 @@
|
||||
"@tailwindcss/vite": "4.1.11",
|
||||
"@tsconfig/bun": "1.0.9",
|
||||
"@tsconfig/node22": "22.0.2",
|
||||
"@types/bun": "1.3.11",
|
||||
"@types/bun": "1.3.12",
|
||||
"@types/cross-spawn": "6.0.6",
|
||||
"@types/luxon": "3.7.1",
|
||||
"@types/node": "22.13.9",
|
||||
"@types/semver": "7.7.1",
|
||||
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|
||||
"ai": "6.0.158",
|
||||
"ai": "6.0.168",
|
||||
"cross-spawn": "7.0.6",
|
||||
"diff": "8.0.2",
|
||||
"dompurify": "3.3.1",
|
||||
@@ -740,7 +742,7 @@
|
||||
|
||||
"@ai-sdk/alibaba": ["@ai-sdk/alibaba@1.0.17", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZbE+U5bWz2JBc5DERLowx5+TKbjGBE93LqKZAWvuEn7HOSQMraxFMZuc0ST335QZJAyfBOzh7m1mPQ+y7EaaoA=="],
|
||||
|
||||
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.93", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.69", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-hcXDU8QDwpAzLVTuY932TQVlIij9+iaVTxc5mPGY6yb//JMAAC5hMVhg93IrxlrxWLvMgjezNgoZGwquR+SGnw=="],
|
||||
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.96", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.71", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Mc4Ias2jRMD1jOB6xWtKNPdhECeuCZyIlbr9EAGfBnyBt++sS13ziZh9qv9TdyMCAZJ7xoQcpbchoRJcKwPdpA=="],
|
||||
|
||||
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.64", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-rwLi/Rsuj2pYniQXIrvClHvXDzgM4UQHHnvHTWEF14efnlKclG/1ghpNC+adsRujAbCTr6gRsSbDE2vEqriV7g=="],
|
||||
|
||||
@@ -760,11 +762,11 @@
|
||||
|
||||
"@ai-sdk/fireworks": ["@ai-sdk/fireworks@2.0.46", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XRKR0zgRyegdmtK5CDUEjlyRp0Fo+XVCdoG+301U1SGtgRIAYG3ObVtgzVJBVpJdHFSLHuYeLTnNiQoUxD7+FQ=="],
|
||||
|
||||
"@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.97", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ERHmVGX30YKTwxObuHQzNqoOf8Nb5WwYMDBn34e3TGGVn0vLEXwMimo7uRVTbhhi4gfu9WtwYTE4x1+csZok1w=="],
|
||||
"@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.104", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZKX5n74io8VIRlhIMSLWVlvT3sXC8Z7cZ9GHuWBWZDVi96+62AIsWuLGvMfcBA1STYuSoDrp6rIziZmvrTq0TA=="],
|
||||
|
||||
"@ai-sdk/google": ["@ai-sdk/google@3.0.63", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-RfOZWVMYSPu2sPRfGajrauWAZ9BSaRopSn+AszkKWQ1MFj8nhaXvCqRHB5pBQUaHTfZKagvOmMpNfa/s3gPLgQ=="],
|
||||
|
||||
"@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@4.0.109", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.69", "@ai-sdk/google": "3.0.63", "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-QzQ+DgOoSYlkU4mK0H+iaCaW1bl5zOimH9X2E2oylcVyUtAdCuduQ959Uw1ygW3l09J2K/ceEDtK8OUPHyOA7g=="],
|
||||
"@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@4.0.112", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.71", "@ai-sdk/google": "3.0.64", "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cSfHCkM+9ZrFtQWIN1WlV93JPD+isGSdFxKj7u1L9m2aLVZajlXdcE41GL9hMt7ld7bZYE4NnZ+4VLxBAHE+Eg=="],
|
||||
|
||||
"@ai-sdk/groq": ["@ai-sdk/groq@3.0.31", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XbbugpnFmXGu2TlXiq8KUJskP6/VVbuFcnFIGDzDIB/Chg6XHsNnqrTF80Zxkh0Pd3+NvbM+2Uqrtsndk6bDAg=="],
|
||||
|
||||
@@ -1468,6 +1470,8 @@
|
||||
|
||||
"@npmcli/arborist": ["@npmcli/arborist@9.4.0", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^5.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/map-workspaces": "^5.0.0", "@npmcli/metavuln-calculator": "^9.0.2", "@npmcli/name-from-folder": "^4.0.0", "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/query": "^5.0.0", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.0", "bin-links": "^6.0.0", "cacache": "^20.0.1", "common-ancestor-path": "^2.0.0", "hosted-git-info": "^9.0.0", "json-stringify-nice": "^1.1.4", "lru-cache": "^11.2.1", "minimatch": "^10.0.3", "nopt": "^9.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.0", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "pacote": "^21.0.2", "parse-conflict-json": "^5.0.1", "proc-log": "^6.0.0", "proggy": "^4.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "semver": "^7.3.7", "ssri": "^13.0.0", "treeverse": "^3.0.0", "walk-up-path": "^4.0.0" }, "bin": { "arborist": "bin/index.js" } }, "sha512-4Bm8hNixJG/sii1PMnag0V9i/sGOX9VRzFrUiZMSBJpGlLR38f+Btl85d07G9GL56xO0l0OZjvrGNYsDYp0xKA=="],
|
||||
|
||||
"@npmcli/config": ["@npmcli/config@10.8.1", "", { "dependencies": { "@npmcli/map-workspaces": "^5.0.0", "@npmcli/package-json": "^7.0.0", "ci-info": "^4.0.0", "ini": "^6.0.0", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "walk-up-path": "^4.0.0" } }, "sha512-MAYk9IlIGiyC0c9fnjdBSQfIFPZT0g1MfeSiD1UXTq2zJOLX55jS9/sETJHqw/7LN18JjITrhYfgCfapbmZHiQ=="],
|
||||
|
||||
"@npmcli/fs": ["@npmcli/fs@5.0.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og=="],
|
||||
|
||||
"@npmcli/git": ["@npmcli/git@7.0.2", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/promise-spawn": "^9.0.0", "ini": "^6.0.0", "lru-cache": "^11.2.1", "npm-pick-manifest": "^11.0.1", "proc-log": "^6.0.0", "semver": "^7.3.5", "which": "^6.0.0" } }, "sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg=="],
|
||||
@@ -1562,8 +1566,6 @@
|
||||
|
||||
"@opencode-ai/sdk": ["@opencode-ai/sdk@workspace:packages/sdk/js"],
|
||||
|
||||
"@opencode-ai/server": ["@opencode-ai/server@workspace:packages/server"],
|
||||
|
||||
"@opencode-ai/shared": ["@opencode-ai/shared@workspace:packages/shared"],
|
||||
|
||||
"@opencode-ai/slack": ["@opencode-ai/slack@workspace:packages/slack"],
|
||||
@@ -1590,7 +1592,7 @@
|
||||
|
||||
"@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.214.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.214.0", "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1", "@opentelemetry/sdk-logs": "0.214.0", "@opentelemetry/sdk-metrics": "2.6.1", "@opentelemetry/sdk-trace-base": "2.6.1", "protobufjs": "^7.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-DSaYcuBRh6uozfsWN3R8HsN0yDhCuWP7tOFdkUOVaWD1KVJg8m4qiLUsg/tNhTLS9HUYUcwNpwL2eroLtsZZ/w=="],
|
||||
|
||||
"@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
|
||||
"@opentelemetry/resources": ["@opentelemetry/resources@2.2.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A=="],
|
||||
|
||||
"@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.214.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.214.0", "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-zf6acnScjhsaBUU22zXZ/sLWim1dfhUAbGXdMmHmNG3LfBnQ3DKsOCITb2IZwoUsNNMTogqFKBnlIPPftUgGwA=="],
|
||||
|
||||
@@ -1602,21 +1604,21 @@
|
||||
|
||||
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="],
|
||||
|
||||
"@opentui/core": ["@opentui/core@0.1.99", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.99", "@opentui/core-darwin-x64": "0.1.99", "@opentui/core-linux-arm64": "0.1.99", "@opentui/core-linux-x64": "0.1.99", "@opentui/core-win32-arm64": "0.1.99", "@opentui/core-win32-x64": "0.1.99", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-I3+AEgGzqNWIpWX9g2WOscSPwtQDNOm4KlBjxBWCZjLxkF07u77heWXF7OiAdhKLtNUW6TFiyt6yznqAZPdG3A=="],
|
||||
"@opentui/core": ["@opentui/core@0.1.103", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.103", "@opentui/core-darwin-x64": "0.1.103", "@opentui/core-linux-arm64": "0.1.103", "@opentui/core-linux-x64": "0.1.103", "@opentui/core-win32-arm64": "0.1.103", "@opentui/core-win32-x64": "0.1.103", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-PWVv/bDmlk1i6X1f0zXs+jSaTrQ/ByX8wFbP2WinOObTGf//UbcRP4dbWxPXvOyka9QlmRBG/7GbloQSIStyVw=="],
|
||||
|
||||
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.99", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bzVrqeX2vb5iWrc/ftOUOqeUY8XO+qSgoTwj5TXHuwagavgwD3Hpeyjx8+icnTTeM4pao0som1WR9xfye6/X5Q=="],
|
||||
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.103", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lxCyedDkcen12IgBtXjkJ7iY66xa7VC4nxRNKCUeLY2ZP9hUE1AsDtbyQzqY+BQadsI/ZME9STzaHDCUFg0TpA=="],
|
||||
|
||||
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.99", "", { "os": "darwin", "cpu": "x64" }, "sha512-VE4FrXBYpkxnvkqcCV1a8aN9jyyMJMihVW+V2NLCtp+4yQsj0AapG5TiUSN76XnmSZRptxDy5rBmEempeoIZbg=="],
|
||||
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.103", "", { "os": "darwin", "cpu": "x64" }, "sha512-QMYD+zUDGQliJ6m5nuNvA72jtluFeyVMoHkuA5m/Xmed/u8eLfahAKmDj3kY66ntUroPHWevcpbpvd7NCFEoFQ=="],
|
||||
|
||||
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.99", "", { "os": "linux", "cpu": "arm64" }, "sha512-viXQsbpS7yHjYkl7+am32JdvG96QU9lvHh1UiZtpOxcNUUqiYmA2ZwZFPD2Bi54jNyj5l2hjH6YkD3DzE2FEWA=="],
|
||||
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.103", "", { "os": "linux", "cpu": "arm64" }, "sha512-GzOvNr9dN6JaQ9qs7m8E75wLAHwT5CyxqkE6rEr1BO23/d2Ix7e3GYw/JRY5VnTge+eXrfDVbqNtPcQamUNiEA=="],
|
||||
|
||||
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.99", "", { "os": "linux", "cpu": "x64" }, "sha512-WLoEFINOSp0tZSR9y4LUuGc7n4Y7H1wcpjUPzQ9vChkYDXrfZltEanzoDWbDcQ4kZQW5tHVC7LrZHpAsRLwFZg=="],
|
||||
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.103", "", { "os": "linux", "cpu": "x64" }, "sha512-odywllco5zUKNc60uD3JKaCybK64u6BfmpScs4a8Qn89yH/yk23bzWXDRWaGgQdY65L2/VCbcGs1ezA1S/2YTw=="],
|
||||
|
||||
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.99", "", { "os": "win32", "cpu": "arm64" }, "sha512-yWMOLWCEO8HdrctU1dMkgZC8qGkiO4Dwr4/e11tTvVpRmYhDsP/IR89ZjEEtOwnKwFOFuB/MxvflqaEWVQ2g5Q=="],
|
||||
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.103", "", { "os": "win32", "cpu": "arm64" }, "sha512-tZL5w3Y0JnO7RkIvfuNDAzJn0j6+JIYl6M8DgPM5p8AQt+162S8LmbumzmqQLZl4cEev2eN7/tw72WIk6b+/CQ=="],
|
||||
|
||||
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.99", "", { "os": "win32", "cpu": "x64" }, "sha512-aYRlsL2w8YRL6vPd7/hrqlNVkXU3QowWb01TOvAcHS8UAsXaGFUr47kSDyjxDi1wg1MzmVduCfsC7T3NoThV1w=="],
|
||||
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.103", "", { "os": "win32", "cpu": "x64" }, "sha512-wqnibt/OE5ldSzVPxEbriA0TjI2B11CJl4uJoLxTZ47KDx7tAFIMdhBf9IRAGNCSbcDuZ8ZGEFhV+SLaftkrlw=="],
|
||||
|
||||
"@opentui/solid": ["@opentui/solid@0.1.99", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.99", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.10", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.11" } }, "sha512-DrqqO4h2V88FmeIP2cErYkMU0ZK5MrUsZw3w6IzZpoXyyiL4/9qpWzUq+CXx+r16VP2iGxDJwGKUmtFAzUch2Q=="],
|
||||
"@opentui/solid": ["@opentui/solid@0.1.103", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.103", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.10", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.11" } }, "sha512-L28WFBs17Z5JXkJhPagLy8tUamkttDaaQDdb2KEO01IQ9r81yLBRpYqD/lHp6UoSISXgwQVDQ9yNtxwR1BQZvQ=="],
|
||||
|
||||
"@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
|
||||
|
||||
@@ -1688,6 +1690,56 @@
|
||||
|
||||
"@oxc-transform/binding-win32-x64-msvc": ["@oxc-transform/binding-win32-x64-msvc@0.96.0", "", { "os": "win32", "cpu": "x64" }, "sha512-0fI0P0W7bSO/GCP/N5dkmtB9vBqCA4ggo1WmXTnxNJVmFFOtcA1vYm1I9jl8fxo+sucW2WnlpnI4fjKdo3JKxA=="],
|
||||
|
||||
"@oxlint-tsgolint/darwin-arm64": ["@oxlint-tsgolint/darwin-arm64@0.21.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-P20j3MLqfwIT+94qGU3htC7dWp4pXGZW1p1p7FRUzu1aopq7c9nPCgf0W/WjktqQ57+iuTq9mbSlwWinl6+H1A=="],
|
||||
|
||||
"@oxlint-tsgolint/darwin-x64": ["@oxlint-tsgolint/darwin-x64@0.21.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-81TmmuBcPedEA0MwRmObuQuXnCprS1UiHQWGe7pseqNAJzUWXeAPrayqKTACX92VpruJI+yvY0XJrFp11PpcTA=="],
|
||||
|
||||
"@oxlint-tsgolint/linux-arm64": ["@oxlint-tsgolint/linux-arm64@0.21.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-sbjBr6zDduX8rNO0PTjhf7VYLCPWqdijWiMPp8e10qu6Tam1GdaVLaLlX8QrNupTgglO1GvqqgY/jcacWL8a6g=="],
|
||||
|
||||
"@oxlint-tsgolint/linux-x64": ["@oxlint-tsgolint/linux-x64@0.21.0", "", { "os": "linux", "cpu": "x64" }, "sha512-jNrOcy53R5TJQfrK444Cm60bW9437xDoxPbm3AdvFSo/fhdFMllawc7uZC2Wzr+EAjTkW13K8R4QHzsUdBG9fQ=="],
|
||||
|
||||
"@oxlint-tsgolint/win32-arm64": ["@oxlint-tsgolint/win32-arm64@0.21.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-xWeRxJJILDE4b9UqHEWGBxcBc1TUS6zWHhxcyxTZMwf4q3wdKeu0OHYAcwLGJzoSjEIf6FTjyfPiRNil2oqsdg=="],
|
||||
|
||||
"@oxlint-tsgolint/win32-x64": ["@oxlint-tsgolint/win32-x64@0.21.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Ob9AA9teI8ckPo1whV1smLr5NrqwgBv/8boDbK0YZG+fKgNGRwr1hBj1ORgFWOQaUBv+5njp5A0RAfJJjQ95QQ=="],
|
||||
|
||||
"@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.60.0", "", { "os": "android", "cpu": "arm" }, "sha512-YdeJKaZckDQL1qa62a1aKq/goyq48aX3yOxaaWqWb4sau4Ee4IiLbamftNLU3zbePky6QsDj6thnSSzHRBjDfA=="],
|
||||
|
||||
"@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.60.0", "", { "os": "android", "cpu": "arm64" }, "sha512-7ANS7PpXCfq84xZQ8E5WPs14gwcuPcl+/8TFNXfpSu0CQBXz3cUo2fDpHT8v8HJN+Ut02eacvMAzTnc9s6X4tw=="],
|
||||
|
||||
"@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.60.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-pJsgd9AfplLGBm1fIr25V6V14vMrayhx4uIQvlfH7jWs2SZwSrvi3TfgfJySB8T+hvyEH8K2zXljQiUnkgUnfQ=="],
|
||||
|
||||
"@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.60.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ue1aXHX49ivwflKqGJc7zcd/LeLgbhaTcDCQStgx5x06AXgjEAZmvrlMuIkWd4AL4FHQe6QJ9f33z04Cg448VQ=="],
|
||||
|
||||
"@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.60.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-YCyQzsQtusQw+gNRW9rRTifSO+Dt/+dtCl2NHoDMZqJlRTEZ/Oht9YnuporI9yiTx7+cB+eqzX3MtHHVHGIWhg=="],
|
||||
|
||||
"@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.60.0", "", { "os": "linux", "cpu": "arm" }, "sha512-c7dxM2Zksa45Qw16i2iGY3Fti2NirJ38FrsBsKw+qcJ0OtqTsBgKJLF0xV+yLG56UH01Z8WRPgsw31e0MoRoGQ=="],
|
||||
|
||||
"@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.60.0", "", { "os": "linux", "cpu": "arm" }, "sha512-ZWALoA42UYqBEP1Tbw9OWURgFGS1nWj2AAvLdY6ZcGx/Gj93qVCBKjcvwXMupZibYwFbi9s/rzqkZseb/6gVtQ=="],
|
||||
|
||||
"@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.60.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-tpy+1w4p9hN5CicMCxqNy6ymfRtV5ayE573vFNjp1k1TN/qhLFgflveZoE/0++RlkHikBz2vY545NWm/hp7big=="],
|
||||
|
||||
"@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.60.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-eDYDXZGhQAXyn6GwtwiX/qcLS0HlOLPJ/+iiIY8RYr+3P8oKBmgKxADLlniL6FtWfE7pPk7IGN9/xvDEvDvFeg=="],
|
||||
|
||||
"@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.60.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nxehly5XYBHUWI9VJX1bqCf9j/B43DaK/aS/T1fcxCpX3PA4Rm9BB54nPD1CKayT8xg6REN1ao+01hSRNgy8OA=="],
|
||||
|
||||
"@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.60.0", "", { "os": "linux", "cpu": "none" }, "sha512-j1qf/NaUfOWQutjeoooNG1Q0zsK0XGmSu1uDLq3cctquRF3j7t9Hxqf/76ehCc5GEUAanth2W4Fa+XT1RFg/nw=="],
|
||||
|
||||
"@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.60.0", "", { "os": "linux", "cpu": "none" }, "sha512-YELKPRefQ/q/h3RUmeRfPCUhh2wBvgV1RyZ/F9M9u8cDyXsQW2ojv1DeWQTt466yczDITjZnIOg/s05pk7Ve2A=="],
|
||||
|
||||
"@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.60.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-JkO3C6Gki7Y6h/MiIkFKvHFOz98/YWvQ4WYbK9DLXACMP2rjULzkeGyAzorJE5S1dzLQGFgeqvN779kSFwoV1g=="],
|
||||
|
||||
"@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.60.0", "", { "os": "linux", "cpu": "x64" }, "sha512-XjKHdFVCpZZZSWBCKyyqCq65s2AKXykMXkjLoKYODrD+f5toLhlwsMESscu8FbgnJQ4Y/dpR/zdazsahmgBJIA=="],
|
||||
|
||||
"@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.60.0", "", { "os": "linux", "cpu": "x64" }, "sha512-js29ZWIuPhNWzY8NC7KoffEMEeWG105vbmm+8EOJsC+T/jHBiKIJEUF78+F/IrgEWMMP9N0kRND4Pp75+xAhKg=="],
|
||||
|
||||
"@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.60.0", "", { "os": "none", "cpu": "arm64" }, "sha512-H+PUITKHk04stFpWj3x3Kg08Afp/bcXSBi0EhasR5a0Vw7StXHTzdl655PUI0fB4qdh2Wsu6Dsi+3ACxPoyQnA=="],
|
||||
|
||||
"@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.60.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-WA/yc7f7ZfCefBXVzNHn1Ztulb1EFwNBb4jMZ6pjML0zz6pHujlF3Q3jySluz3XHl/GNeMTntG1seUBWVMlMag=="],
|
||||
|
||||
"@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.60.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-33YxL1sqwYNZXtn3MD/4dno6s0xeedXOJlT1WohkVD565WvohClZUr7vwKdAk954n4xiEWJkewiCr+zLeq7AeA=="],
|
||||
|
||||
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.60.0", "", { "os": "win32", "cpu": "x64" }, "sha512-JOro4ZcfBLamJCyfURQmOQByoorgOdx3ZjAkSqnb/CyG/i+lN3KoV5LAgk5ZAW6DPq7/Cx7n23f8DuTWXTWgyQ=="],
|
||||
|
||||
"@pagefind/darwin-arm64": ["@pagefind/darwin-arm64@1.5.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ=="],
|
||||
|
||||
"@pagefind/darwin-x64": ["@pagefind/darwin-x64@1.5.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw=="],
|
||||
@@ -2250,7 +2302,7 @@
|
||||
|
||||
"@types/braces": ["@types/braces@3.0.5", "", {}, "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="],
|
||||
"@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="],
|
||||
|
||||
"@types/cacache": ["@types/cacache@20.0.1", "", { "dependencies": { "@types/node": "*", "minipass": "*" } }, "sha512-QlKW3AFoFr/hvPHwFHMIVUH/ZCYeetBNou3PCmxu5LaNDvrtBlPJtIA6uhmU9JRt9oxj7IYoqoLcpxtzpPiTcw=="],
|
||||
|
||||
@@ -2408,7 +2460,7 @@
|
||||
|
||||
"@valibot/to-json-schema": ["@valibot/to-json-schema@1.6.0", "", { "peerDependencies": { "valibot": "^1.3.0" } }, "sha512-d6rYyK5KVa2XdqamWgZ4/Nr+cXhxjy7lmpe6Iajw15J/jmU+gyxl2IEd1Otg1d7Rl3gOQL5reulnSypzBtYy1A=="],
|
||||
|
||||
"@vercel/oidc": ["@vercel/oidc@3.1.0", "", {}, "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w=="],
|
||||
"@vercel/oidc": ["@vercel/oidc@3.2.0", "", {}, "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug=="],
|
||||
|
||||
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],
|
||||
|
||||
@@ -2468,7 +2520,7 @@
|
||||
|
||||
"agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="],
|
||||
|
||||
"ai": ["ai@6.0.158", "", { "dependencies": { "@ai-sdk/gateway": "3.0.95", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-gLTp1UXFtMqKUi3XHs33K7UFglbvojkxF/aq337TxnLGOhHIW9+GyP2jwW4hYX87f1es+wId3VQoPRRu9zEStQ=="],
|
||||
"ai": ["ai@6.0.168", "", { "dependencies": { "@ai-sdk/gateway": "3.0.104", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-2HqCJuO+1V2aV7vfYs5LFEUfxbkGX+5oa54q/gCCTL7KLTdbxcCu5D7TdLA5kwsrs3Szgjah9q6D9tpjHM3hUQ=="],
|
||||
|
||||
"ai-gateway-provider": ["ai-gateway-provider@3.1.2", "", { "optionalDependencies": { "@ai-sdk/amazon-bedrock": "^4.0.62", "@ai-sdk/anthropic": "^3.0.46", "@ai-sdk/azure": "^3.0.31", "@ai-sdk/cerebras": "^2.0.34", "@ai-sdk/cohere": "^3.0.21", "@ai-sdk/deepgram": "^2.0.20", "@ai-sdk/deepseek": "^2.0.20", "@ai-sdk/elevenlabs": "^2.0.20", "@ai-sdk/fireworks": "^2.0.34", "@ai-sdk/google": "^3.0.30", "@ai-sdk/google-vertex": "^4.0.61", "@ai-sdk/groq": "^3.0.24", "@ai-sdk/mistral": "^3.0.20", "@ai-sdk/openai": "^3.0.30", "@ai-sdk/perplexity": "^3.0.19", "@ai-sdk/xai": "^3.0.57", "@openrouter/ai-sdk-provider": "^2.2.3" }, "peerDependencies": { "@ai-sdk/openai-compatible": "^2.0.0", "@ai-sdk/provider": "^3.0.0", "@ai-sdk/provider-utils": "^4.0.0", "ai": "^6.0.0" } }, "sha512-krGNnJSoO/gJ7Hbe5nQDlsBpDUGIBGtMQTRUaW7s1MylsfvLduba0TLWzQaGtOmNRkP0pGhtGlwsnS6FNQMlyw=="],
|
||||
|
||||
@@ -2668,7 +2720,7 @@
|
||||
|
||||
"bun-pty": ["bun-pty@0.4.8", "", {}, "sha512-rO70Mrbr13+jxHHHu2YBkk2pNqrJE5cJn29WE++PUr+GFA0hq/VgtQPZANJ8dJo6d7XImvBk37Innt8GM7O28w=="],
|
||||
|
||||
"bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="],
|
||||
"bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="],
|
||||
|
||||
"bun-webgpu": ["bun-webgpu@0.1.5", "", { "dependencies": { "@webgpu/types": "^0.1.60" }, "optionalDependencies": { "bun-webgpu-darwin-arm64": "^0.1.5", "bun-webgpu-darwin-x64": "^0.1.5", "bun-webgpu-linux-x64": "^0.1.5", "bun-webgpu-win32-x64": "^0.1.5" } }, "sha512-91/K6S5whZKX7CWAm9AylhyKrLGRz6BUiiPiM/kXadSnD4rffljCD/q9cNFftm5YXhx4MvLqw33yEilxogJvwA=="],
|
||||
|
||||
@@ -2978,7 +3030,7 @@
|
||||
|
||||
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
||||
|
||||
"electron": ["electron@40.4.1", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-N1ZXybQZL8kYemO8vAeh9nrk4mSvqlAO8xs0QCHkXIvRnuB/7VGwEehjvQbsU5/f4bmTKpG+2GQERe/zmKpudQ=="],
|
||||
"electron": ["electron@41.2.1", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-teeRThiYGTPKf/2yOW7zZA1bhb91KEQ4yLBPOg7GxpmnkLFLugKgQaAKOrCgdzwsXh/5mFIfmkm+4+wACJKwaA=="],
|
||||
|
||||
"electron-builder": ["electron-builder@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", "dmg-builder": "26.8.1", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-uWhx1r74NGpCagG0ULs/P9Nqv2nsoo+7eo4fLUOB8L8MdWltq9odW/uuLXMFCDGnPafknYLZgjNX0ZIFRzOQAw=="],
|
||||
|
||||
@@ -3258,7 +3310,7 @@
|
||||
|
||||
"get-tsconfig": ["get-tsconfig@4.13.8", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-J87BxkLXykmisLQ+KA4x2+O6rVf+PJrtFUO8lGyiRg4lyxJLJ8/v0sRAKdVZQOy6tR6lMRAF1NqzCf9BQijm0w=="],
|
||||
|
||||
"ghostty-web": ["ghostty-web@github:anomalyco/ghostty-web#4af877d", {}, "anomalyco-ghostty-web-4af877d", "sha512-fbEK8mtr7ar4ySsF+JUGjhaZrane7dKphanN+SxHt5XXI6yLMAh/Hpf6sNCOyyVa2UlGCd7YpXG/T2v2RUAX+A=="],
|
||||
"ghostty-web": ["ghostty-web@github:anomalyco/ghostty-web#20bd361", {}, "anomalyco-ghostty-web-20bd361", "sha512-dW0nwaiBBcun9y5WJSvm3HxDLe5o9V0xLCndQvWonRVubU8CS1PHxZpLffyPt1YujPWC13ez03aWxcuKBPYYGQ=="],
|
||||
|
||||
"gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="],
|
||||
|
||||
@@ -3266,7 +3318,7 @@
|
||||
|
||||
"github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
|
||||
|
||||
"gitlab-ai-provider": ["gitlab-ai-provider@6.4.2", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=3.0.0", "@ai-sdk/provider-utils": ">=4.0.0" } }, "sha512-Wyw6uslCuipBOr/NYwAtpgXEUJj68iJY5aekad2DjePN99JetKVQBqkLgAy9PZp2EA4OuscfRQu9qKIBN/evNw=="],
|
||||
"gitlab-ai-provider": ["gitlab-ai-provider@6.6.0", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=3.0.0", "@ai-sdk/provider-utils": ">=4.0.0" } }, "sha512-jUxYnKA4XQaPc3wxACDZ8bPDXO0Mzx7cZaBDxbT2uGgLqtGZmSi+9tVNIg7louSS+s/ioVra3SoUz3iOFVhKPA=="],
|
||||
|
||||
"glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="],
|
||||
|
||||
@@ -4068,6 +4120,10 @@
|
||||
|
||||
"oxc-transform": ["oxc-transform@0.96.0", "", { "optionalDependencies": { "@oxc-transform/binding-android-arm64": "0.96.0", "@oxc-transform/binding-darwin-arm64": "0.96.0", "@oxc-transform/binding-darwin-x64": "0.96.0", "@oxc-transform/binding-freebsd-x64": "0.96.0", "@oxc-transform/binding-linux-arm-gnueabihf": "0.96.0", "@oxc-transform/binding-linux-arm-musleabihf": "0.96.0", "@oxc-transform/binding-linux-arm64-gnu": "0.96.0", "@oxc-transform/binding-linux-arm64-musl": "0.96.0", "@oxc-transform/binding-linux-riscv64-gnu": "0.96.0", "@oxc-transform/binding-linux-s390x-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-musl": "0.96.0", "@oxc-transform/binding-wasm32-wasi": "0.96.0", "@oxc-transform/binding-win32-arm64-msvc": "0.96.0", "@oxc-transform/binding-win32-x64-msvc": "0.96.0" } }, "sha512-dQPNIF+gHpSkmC0+Vg9IktNyhcn28Y8R3eTLyzn52UNymkasLicl3sFAtz7oEVuFmCpgGjaUTKkwk+jW2cHpDQ=="],
|
||||
|
||||
"oxlint": ["oxlint@1.60.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.60.0", "@oxlint/binding-android-arm64": "1.60.0", "@oxlint/binding-darwin-arm64": "1.60.0", "@oxlint/binding-darwin-x64": "1.60.0", "@oxlint/binding-freebsd-x64": "1.60.0", "@oxlint/binding-linux-arm-gnueabihf": "1.60.0", "@oxlint/binding-linux-arm-musleabihf": "1.60.0", "@oxlint/binding-linux-arm64-gnu": "1.60.0", "@oxlint/binding-linux-arm64-musl": "1.60.0", "@oxlint/binding-linux-ppc64-gnu": "1.60.0", "@oxlint/binding-linux-riscv64-gnu": "1.60.0", "@oxlint/binding-linux-riscv64-musl": "1.60.0", "@oxlint/binding-linux-s390x-gnu": "1.60.0", "@oxlint/binding-linux-x64-gnu": "1.60.0", "@oxlint/binding-linux-x64-musl": "1.60.0", "@oxlint/binding-openharmony-arm64": "1.60.0", "@oxlint/binding-win32-arm64-msvc": "1.60.0", "@oxlint/binding-win32-ia32-msvc": "1.60.0", "@oxlint/binding-win32-x64-msvc": "1.60.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.18.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-tnRzTWiWJ9pg3ftRWnD0+Oqh78L6ZSwcEudvCZaER0PIqiAnNyXj5N1dPwjmNpDalkKS9m/WMLN1CTPUBPmsgw=="],
|
||||
|
||||
"oxlint-tsgolint": ["oxlint-tsgolint@0.21.0", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "0.21.0", "@oxlint-tsgolint/darwin-x64": "0.21.0", "@oxlint-tsgolint/linux-arm64": "0.21.0", "@oxlint-tsgolint/linux-x64": "0.21.0", "@oxlint-tsgolint/win32-arm64": "0.21.0", "@oxlint-tsgolint/win32-x64": "0.21.0" }, "bin": { "tsgolint": "bin/tsgolint.js" } }, "sha512-HiWPhANwRnN1pZJQ2SgNB3WRR+1etLJHmRzQ/MJhyINsEIaOUCjxhlXJKbEaVUwdnyXwRWqo/P9Fx21lz0/mSg=="],
|
||||
|
||||
"p-cancelable": ["p-cancelable@2.1.1", "", {}, "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="],
|
||||
|
||||
"p-defer": ["p-defer@3.0.0", "", {}, "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw=="],
|
||||
@@ -4430,8 +4486,6 @@
|
||||
|
||||
"rimraf": ["rimraf@2.6.3", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA=="],
|
||||
|
||||
"ripgrep": ["ripgrep@0.3.1", "", { "bin": { "rg": "lib/rg.mjs", "ripgrep": "lib/rg.mjs" } }, "sha512-6bDtNIBh1qPviVIU685/4uv0Ap5t8eS4wiJhy/tR2LdIeIey9CVasENlGS+ul3HnTmGANIp7AjnfsztsRmALfQ=="],
|
||||
|
||||
"roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="],
|
||||
|
||||
"rollup": ["rollup@4.60.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.1", "@rollup/rollup-android-arm64": "4.60.1", "@rollup/rollup-darwin-arm64": "4.60.1", "@rollup/rollup-darwin-x64": "4.60.1", "@rollup/rollup-freebsd-arm64": "4.60.1", "@rollup/rollup-freebsd-x64": "4.60.1", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", "@rollup/rollup-linux-arm-musleabihf": "4.60.1", "@rollup/rollup-linux-arm64-gnu": "4.60.1", "@rollup/rollup-linux-arm64-musl": "4.60.1", "@rollup/rollup-linux-loong64-gnu": "4.60.1", "@rollup/rollup-linux-loong64-musl": "4.60.1", "@rollup/rollup-linux-ppc64-gnu": "4.60.1", "@rollup/rollup-linux-ppc64-musl": "4.60.1", "@rollup/rollup-linux-riscv64-gnu": "4.60.1", "@rollup/rollup-linux-riscv64-musl": "4.60.1", "@rollup/rollup-linux-s390x-gnu": "4.60.1", "@rollup/rollup-linux-x64-gnu": "4.60.1", "@rollup/rollup-linux-x64-musl": "4.60.1", "@rollup/rollup-openbsd-x64": "4.60.1", "@rollup/rollup-openharmony-arm64": "4.60.1", "@rollup/rollup-win32-arm64-msvc": "4.60.1", "@rollup/rollup-win32-ia32-msvc": "4.60.1", "@rollup/rollup-win32-x64-gnu": "4.60.1", "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w=="],
|
||||
@@ -5102,7 +5156,11 @@
|
||||
|
||||
"@ai-sdk/alibaba/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
|
||||
|
||||
"@ai-sdk/amazon-bedrock/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.69", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-LshR7X3pFugY0o41G2VKTmg1XoGpSl7uoYWfzk6zjVZLhCfeFiwgpOga+eTV4XY1VVpZwKVqRnkDbIL7K2eH5g=="],
|
||||
"@ai-sdk/amazon-bedrock/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.71", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-bUWOzrzR0gJKJO/PLGMR4uH2dqEgqGhrsCV+sSpk4KtOEnUQlfjZI/F7BFlqSvVpFbjdgYRRLysAeEZpJ6S1lg=="],
|
||||
|
||||
"@ai-sdk/amazon-bedrock/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.13", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.0", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-vYahwBAtRaAcFbOmE9aLr12z7RiHYDSLcnogSdxfm7kKfsNa3wH+NU5r7vTeB5rKvLsWyPjVX8iH94brP7umiQ=="],
|
||||
|
||||
"@ai-sdk/amazon-bedrock/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||
|
||||
"@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
||||
|
||||
@@ -5116,7 +5174,9 @@
|
||||
|
||||
"@ai-sdk/fireworks/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
|
||||
|
||||
"@ai-sdk/google-vertex/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.69", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-LshR7X3pFugY0o41G2VKTmg1XoGpSl7uoYWfzk6zjVZLhCfeFiwgpOga+eTV4XY1VVpZwKVqRnkDbIL7K2eH5g=="],
|
||||
"@ai-sdk/google-vertex/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.71", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-bUWOzrzR0gJKJO/PLGMR4uH2dqEgqGhrsCV+sSpk4KtOEnUQlfjZI/F7BFlqSvVpFbjdgYRRLysAeEZpJ6S1lg=="],
|
||||
|
||||
"@ai-sdk/google-vertex/@ai-sdk/google": ["@ai-sdk/google@3.0.64", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-CbR82EgGPNrj/6q0HtclwuCqe0/pDShyv3nWDP/A9DroujzWXnLMlUJVrgPOsg4b40zQCwwVs2XSKCxvt/4QaA=="],
|
||||
|
||||
"@ai-sdk/google-vertex/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
|
||||
|
||||
@@ -5526,6 +5586,18 @@
|
||||
|
||||
"@opencode-ai/web/@shikijs/transformers": ["@shikijs/transformers@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/types": "3.20.0" } }, "sha512-PrHHMRr3Q5W1qB/42kJW6laqFyWdhrPF2hNR9qjOm1xcSiAO3hAHo7HaVyHE6pMyevmy3i51O8kuGGXC78uK3g=="],
|
||||
|
||||
"@opentelemetry/exporter-trace-otlp-http/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
|
||||
|
||||
"@opentelemetry/otlp-transformer/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
|
||||
|
||||
"@opentelemetry/resources/@opentelemetry/core": ["@opentelemetry/core@2.2.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw=="],
|
||||
|
||||
"@opentelemetry/sdk-logs/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
|
||||
|
||||
"@opentelemetry/sdk-metrics/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
|
||||
|
||||
"@opentelemetry/sdk-trace-base/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
|
||||
|
||||
"@opentui/solid/@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="],
|
||||
|
||||
"@opentui/solid/babel-preset-solid": ["babel-preset-solid@1.9.10", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.3" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.10" }, "optionalPeers": ["solid-js"] }, "sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ=="],
|
||||
@@ -5632,7 +5704,7 @@
|
||||
|
||||
"accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
|
||||
|
||||
"ai/@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.95", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZmUNNbZl3V42xwQzPaNUi+s8eqR2lnrxf0bvB6YbLXpLjHYv0k2Y78t12cNOfY0bxGeuVVTLyk856uLuQIuXEQ=="],
|
||||
"ai-gateway-provider/@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.93", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.69", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-hcXDU8QDwpAzLVTuY932TQVlIij9+iaVTxc5mPGY6yb//JMAAC5hMVhg93IrxlrxWLvMgjezNgoZGwquR+SGnw=="],
|
||||
|
||||
"ai-gateway-provider/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.69", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-LshR7X3pFugY0o41G2VKTmg1XoGpSl7uoYWfzk6zjVZLhCfeFiwgpOga+eTV4XY1VVpZwKVqRnkDbIL7K2eH5g=="],
|
||||
|
||||
@@ -5850,7 +5922,7 @@
|
||||
|
||||
"nypm/tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="],
|
||||
|
||||
"opencode/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.67", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-FFX4P5Fd6lcQJc2OLngZQkbbJHa0IDDZi087Edb8qRZx6h90krtM61ArbMUL8us/7ZUwojCXnyJ/wQ2Eflx2jQ=="],
|
||||
"opencode/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.71", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-bUWOzrzR0gJKJO/PLGMR4uH2dqEgqGhrsCV+sSpk4KtOEnUQlfjZI/F7BFlqSvVpFbjdgYRRLysAeEZpJ6S1lg=="],
|
||||
|
||||
"opencode/@ai-sdk/openai": ["@ai-sdk/openai@3.0.53", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Wld+Rbc05KaUn08uBt06eEuwcgalcIFtIl32Yp+GxuZXUQwOb6YeAuq+C6da4ch6BurFoqEaLemJVwjBb7x+PQ=="],
|
||||
|
||||
|
||||
6
flake.lock
generated
6
flake.lock
generated
@@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1773909469,
|
||||
"narHash": "sha256-vglVrLfHjFIzIdV9A27Ugul6rh3I1qHbbitGW7dk420=",
|
||||
"lastModified": 1776683584,
|
||||
"narHash": "sha256-NuTLMrr10Tng72hurYG8jYQ4XKK8wnpJmOGcPiis96g=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7149c06513f335be57f26fcbbbe34afda923882b",
|
||||
"rev": "9dd5558b06dbdacbf635a3dd36dce1b1a7ee3a89",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -281,7 +281,7 @@ async function assertOpencodeConnected() {
|
||||
})
|
||||
connected = true
|
||||
break
|
||||
} catch (e) {}
|
||||
} catch {}
|
||||
await sleep(300)
|
||||
} while (retry++ < 30)
|
||||
|
||||
@@ -513,7 +513,7 @@ async function subscribeSessionEvents() {
|
||||
const decoder = new TextDecoder()
|
||||
|
||||
let text = ""
|
||||
;(async () => {
|
||||
void (async () => {
|
||||
while (true) {
|
||||
try {
|
||||
const { done, value } = await reader.read()
|
||||
@@ -542,7 +542,7 @@ async function subscribeSessionEvents() {
|
||||
? JSON.stringify(part.state.input)
|
||||
: "Unknown"
|
||||
console.log()
|
||||
console.log(color + `|`, "\x1b[0m\x1b[2m" + ` ${tool.padEnd(7, " ")}`, "", "\x1b[0m" + title)
|
||||
console.log(`${color}|`, `\x1b[0m\x1b[2m ${tool.padEnd(7, " ")}`, "", `\x1b[0m${title}`)
|
||||
}
|
||||
|
||||
if (part.type === "text") {
|
||||
@@ -561,7 +561,7 @@ async function subscribeSessionEvents() {
|
||||
if (evt.properties.info.id !== session.id) continue
|
||||
session = evt.properties.info
|
||||
}
|
||||
} catch (e) {
|
||||
} catch {
|
||||
// Ignore parse errors
|
||||
}
|
||||
}
|
||||
@@ -576,7 +576,7 @@ async function subscribeSessionEvents() {
|
||||
async function summarize(response: string) {
|
||||
try {
|
||||
return await chat(`Summarize the following in less than 40 characters:\n\n${response}`)
|
||||
} catch (e) {
|
||||
} catch {
|
||||
if (isScheduleEvent()) {
|
||||
return "Scheduled task changes"
|
||||
}
|
||||
@@ -776,7 +776,7 @@ async function assertPermissions() {
|
||||
console.log(` permission: ${permission}`)
|
||||
} catch (error) {
|
||||
console.error(`Failed to check permissions: ${error}`)
|
||||
throw new Error(`Failed to check permissions for user ${actor}: ${error}`)
|
||||
throw new Error(`Failed to check permissions for user ${actor}: ${error}`, { cause: error })
|
||||
}
|
||||
|
||||
if (!["admin", "write"].includes(permission)) throw new Error(`User ${actor} does not have write permissions`)
|
||||
|
||||
@@ -236,7 +236,6 @@ new sst.cloudflare.x.SolidStart("Console", {
|
||||
SALESFORCE_INSTANCE_URL,
|
||||
ZEN_BLACK_PRICE,
|
||||
ZEN_LITE_PRICE,
|
||||
new sst.Secret("ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES"),
|
||||
new sst.Secret("ZEN_LIMITS"),
|
||||
new sst.Secret("ZEN_SESSION_SECRET"),
|
||||
...ZEN_MODELS,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { SECRET } from "./secret"
|
||||
import { domain, shortDomain } from "./stage"
|
||||
import { shortDomain } from "./stage"
|
||||
|
||||
const storage = new sst.cloudflare.Bucket("EnterpriseStorage")
|
||||
|
||||
const teams = new sst.cloudflare.x.SolidStart("Teams", {
|
||||
new sst.cloudflare.x.SolidStart("Teams", {
|
||||
domain: shortDomain,
|
||||
path: "packages/enterprise",
|
||||
buildCommand: "bun run build:cloudflare",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"nodeModules": {
|
||||
"x86_64-linux": "sha256-3kpnjBg7AQanyDGTOFdYBFvo9O9Rfnu0Wmi8bY5LpEI=",
|
||||
"aarch64-linux": "sha256-8rQ+SNUiSpA2Ea3NrYNGopHQsnY7Y8qBsXCqL6GMt24=",
|
||||
"aarch64-darwin": "sha256-OASMkW5hnXucV6lSmxrQo73lGSEKN4MQPNGNV0i7jdo=",
|
||||
"x86_64-darwin": "sha256-CmHqXlm8wnLcwSSK0ghxAf+DVurEltMaxrUbWh9/ZGE="
|
||||
"x86_64-linux": "sha256-+G3/s18NZO1Dpc5TsZyix2Npodzei25Svw3nTjfzXW8=",
|
||||
"aarch64-linux": "sha256-39HPencmRYRbyCk/cZIdPFk6ocY1AMlyuN9j25zAKzI=",
|
||||
"aarch64-darwin": "sha256-043korPEjSHKiZ3P+EfWyOfKpgOC7CBpviccviaDa0o=",
|
||||
"x86_64-darwin": "sha256-vsZ7e//rL9e7Cl5kl/Xplvi1fqayljxTLwRSbxvCxeM="
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ stdenvNoCC.mkDerivation {
|
||||
--filter './packages/opencode' \
|
||||
--filter './packages/desktop' \
|
||||
--filter './packages/app' \
|
||||
--filter './packages/shared' \
|
||||
--frozen-lockfile \
|
||||
--ignore-scripts \
|
||||
--no-progress
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
sysctl,
|
||||
makeBinaryWrapper,
|
||||
models-dev,
|
||||
ripgrep,
|
||||
installShellFiles,
|
||||
versionCheckHook,
|
||||
writableTmpDirAsHomeHook,
|
||||
@@ -51,25 +52,25 @@ stdenvNoCC.mkDerivation (finalAttrs: {
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase =
|
||||
''
|
||||
runHook preInstall
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
install -Dm755 dist/opencode-*/bin/opencode $out/bin/opencode
|
||||
install -Dm644 schema.json $out/share/opencode/schema.json
|
||||
''
|
||||
# bun runs sysctl to detect if dunning on rosetta2
|
||||
+ lib.optionalString stdenvNoCC.hostPlatform.isDarwin ''
|
||||
wrapProgram $out/bin/opencode \
|
||||
--prefix PATH : ${
|
||||
lib.makeBinPath [
|
||||
sysctl
|
||||
install -Dm755 dist/opencode-*/bin/opencode $out/bin/opencode
|
||||
install -Dm644 schema.json $out/share/opencode/schema.json
|
||||
|
||||
wrapProgram $out/bin/opencode \
|
||||
--prefix PATH : ${
|
||||
lib.makeBinPath (
|
||||
[
|
||||
ripgrep
|
||||
]
|
||||
}
|
||||
''
|
||||
+ ''
|
||||
runHook postInstall
|
||||
'';
|
||||
# bun runs sysctl to detect if dunning on rosetta2
|
||||
++ lib.optional stdenvNoCC.hostPlatform.isDarwin sysctl
|
||||
)
|
||||
}
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
postInstall = lib.optionalString (stdenvNoCC.buildPlatform.canExecute stdenvNoCC.hostPlatform) ''
|
||||
# trick yargs into also generating zsh completions
|
||||
|
||||
14
package.json
14
package.json
@@ -4,13 +4,14 @@
|
||||
"description": "AI-powered development tool",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"packageManager": "bun@1.3.11",
|
||||
"packageManager": "bun@1.3.13",
|
||||
"scripts": {
|
||||
"dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts",
|
||||
"dev:desktop": "bun --cwd packages/desktop tauri dev",
|
||||
"dev:desktop": "bun --cwd packages/desktop-electron dev",
|
||||
"dev:web": "bun --cwd packages/app dev",
|
||||
"dev:console": "ulimit -n 10240 2>/dev/null; bun run --cwd packages/console/app dev",
|
||||
"dev:storybook": "bun --cwd packages/storybook storybook",
|
||||
"lint": "oxlint",
|
||||
"typecheck": "bun turbo typecheck",
|
||||
"postinstall": "bun run --cwd packages/opencode fix-node-pty",
|
||||
"prepare": "husky",
|
||||
@@ -29,10 +30,12 @@
|
||||
"@effect/opentelemetry": "4.0.0-beta.48",
|
||||
"@effect/platform-node": "4.0.0-beta.48",
|
||||
"@npmcli/arborist": "9.4.0",
|
||||
"@types/bun": "1.3.11",
|
||||
"@types/bun": "1.3.12",
|
||||
"@types/cross-spawn": "6.0.6",
|
||||
"@octokit/rest": "22.0.0",
|
||||
"@hono/zod-validator": "0.4.2",
|
||||
"@opentui/core": "0.1.99",
|
||||
"@opentui/solid": "0.1.99",
|
||||
"ulid": "3.0.1",
|
||||
"@kobalte/core": "0.13.11",
|
||||
"@types/luxon": "3.7.1",
|
||||
@@ -50,7 +53,7 @@
|
||||
"drizzle-kit": "1.0.0-beta.19-d95b7a4",
|
||||
"drizzle-orm": "1.0.0-beta.19-d95b7a4",
|
||||
"effect": "4.0.0-beta.48",
|
||||
"ai": "6.0.158",
|
||||
"ai": "6.0.168",
|
||||
"cross-spawn": "7.0.6",
|
||||
"hono": "4.10.7",
|
||||
"hono-openapi": "1.1.2",
|
||||
@@ -85,6 +88,8 @@
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"glob": "13.0.5",
|
||||
"husky": "9.1.7",
|
||||
"oxlint": "1.60.0",
|
||||
"oxlint-tsgolint": "0.21.0",
|
||||
"prettier": "3.6.2",
|
||||
"semver": "^7.6.0",
|
||||
"sst": "3.18.10",
|
||||
@@ -122,6 +127,7 @@
|
||||
"@types/node": "catalog:"
|
||||
},
|
||||
"patchedDependencies": {
|
||||
"@npmcli/agent@4.0.0": "patches/@npmcli%2Fagent@4.0.0.patch",
|
||||
"@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch",
|
||||
"solid-js@1.9.10": "patches/solid-js@1.9.10.patch"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/app",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
|
||||
Binary file not shown.
@@ -180,8 +180,8 @@ describe("SerializeAddon", () => {
|
||||
await writeAndWait(term, input)
|
||||
|
||||
const origLine = term.buffer.active.getLine(0)
|
||||
const origFg = origLine!.getCell(0)!.getFgColor()
|
||||
const origBg = origLine!.getCell(0)!.getBgColor()
|
||||
const _origFg = origLine!.getCell(0)!.getFgColor()
|
||||
const _origBg = origLine!.getCell(0)!.getBgColor()
|
||||
expect(origLine!.getCell(0)!.isBold()).toBe(1)
|
||||
|
||||
const serialized = addon.serialize({ range: { start: 0, end: 0 } })
|
||||
|
||||
@@ -258,8 +258,8 @@ class StringSerializeHandler extends BaseSerializeHandler {
|
||||
}
|
||||
|
||||
protected _beforeSerialize(rows: number, start: number, _end: number): void {
|
||||
this._allRows = new Array<string>(rows)
|
||||
this._allRowSeparators = new Array<string>(rows)
|
||||
this._allRows = Array.from<string>({ length: rows })
|
||||
this._allRowSeparators = Array.from<string>({ length: rows })
|
||||
this._rowIndex = 0
|
||||
|
||||
this._currentRow = ""
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ThemeProvider } from "@opencode-ai/ui/theme/context"
|
||||
import { MetaProvider } from "@solidjs/meta"
|
||||
import { type BaseRouterProps, Navigate, Route, Router } from "@solidjs/router"
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/solid-query"
|
||||
import { type Duration, Effect } from "effect"
|
||||
import { Effect } from "effect"
|
||||
import {
|
||||
type Component,
|
||||
createMemo,
|
||||
@@ -121,10 +121,10 @@ function SessionProviders(props: ParentProps) {
|
||||
function RouterRoot(props: ParentProps<{ appChildren?: JSX.Element }>) {
|
||||
return (
|
||||
<AppShellProviders>
|
||||
<Suspense fallback={<Loading />}>
|
||||
{props.appChildren}
|
||||
{props.children}
|
||||
</Suspense>
|
||||
{/*<Suspense fallback={<Loading />}>*/}
|
||||
{props.appChildren}
|
||||
{props.children}
|
||||
{/*</Suspense>*/}
|
||||
</AppShellProviders>
|
||||
)
|
||||
}
|
||||
@@ -141,13 +141,11 @@ export function AppBaseProviders(props: ParentProps<{ locale?: Locale }>) {
|
||||
<LanguageProvider locale={props.locale}>
|
||||
<UiI18nBridge>
|
||||
<ErrorBoundary fallback={(error) => <ErrorPage error={error} />}>
|
||||
<QueryProvider>
|
||||
<DialogProvider>
|
||||
<MarkedProvider>
|
||||
<FileComponentProvider component={File}>{props.children}</FileComponentProvider>
|
||||
</MarkedProvider>
|
||||
</DialogProvider>
|
||||
</QueryProvider>
|
||||
<DialogProvider>
|
||||
<MarkedProvider>
|
||||
<FileComponentProvider component={File}>{props.children}</FileComponentProvider>
|
||||
</MarkedProvider>
|
||||
</DialogProvider>
|
||||
</ErrorBoundary>
|
||||
</UiI18nBridge>
|
||||
</LanguageProvider>
|
||||
@@ -156,11 +154,6 @@ export function AppBaseProviders(props: ParentProps<{ locale?: Locale }>) {
|
||||
)
|
||||
}
|
||||
|
||||
const effectMinDuration =
|
||||
(duration: Duration.Input) =>
|
||||
<A, E, R>(e: Effect.Effect<A, E, R>) =>
|
||||
Effect.all([e, Effect.sleep(duration)], { concurrency: "unbounded" }).pipe(Effect.map((v) => v[0]))
|
||||
|
||||
function ConnectionGate(props: ParentProps<{ disableHealthCheck?: boolean }>) {
|
||||
const server = useServer()
|
||||
const checkServerHealth = useCheckServerHealth()
|
||||
@@ -189,32 +182,41 @@ function ConnectionGate(props: ParentProps<{ disableHealthCheck?: boolean }>) {
|
||||
)
|
||||
|
||||
return (
|
||||
<Show
|
||||
when={checkMode() === "blocking" ? !startupHealthCheck.loading : startupHealthCheck.state !== "pending"}
|
||||
<Suspense
|
||||
fallback={
|
||||
<div class="h-dvh w-screen flex flex-col items-center justify-center bg-background-base">
|
||||
<Splash class="w-16 h-20 opacity-50 animate-pulse" />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{/*<Show
|
||||
when={checkMode() === "blocking" ? !startupHealthCheck.loading : startupHealthCheck.state !== "pending"}
|
||||
fallback={
|
||||
<div class="h-dvh w-screen flex flex-col items-center justify-center bg-background-base">
|
||||
<Splash class="w-16 h-20 opacity-50 animate-pulse" />
|
||||
</div>
|
||||
}
|
||||
>*/}
|
||||
{checkMode() === "blocking" ? startupHealthCheck() : startupHealthCheck.latest}
|
||||
<Show
|
||||
when={startupHealthCheck()}
|
||||
fallback={
|
||||
<ConnectionError
|
||||
onRetry={() => {
|
||||
if (checkMode() === "background") healthCheckActions.refetch()
|
||||
if (checkMode() === "background") void healthCheckActions.refetch()
|
||||
}}
|
||||
onServerSelected={(key) => {
|
||||
setCheckMode("blocking")
|
||||
server.setActive(key)
|
||||
healthCheckActions.refetch()
|
||||
void healthCheckActions.refetch()
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{props.children}
|
||||
</Show>
|
||||
</Show>
|
||||
{/*</Show>*/}
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -289,20 +291,22 @@ export function AppInterface(props: {
|
||||
>
|
||||
<ConnectionGate disableHealthCheck={props.disableHealthCheck}>
|
||||
<ServerKey>
|
||||
<GlobalSDKProvider>
|
||||
<GlobalSyncProvider>
|
||||
<Dynamic
|
||||
component={props.router ?? Router}
|
||||
root={(routerProps) => <RouterRoot appChildren={props.children}>{routerProps.children}</RouterRoot>}
|
||||
>
|
||||
<Route path="/" component={HomeRoute} />
|
||||
<Route path="/:dir" component={DirectoryLayout}>
|
||||
<Route path="/" component={SessionIndexRoute} />
|
||||
<Route path="/session/:id?" component={SessionRoute} />
|
||||
</Route>
|
||||
</Dynamic>
|
||||
</GlobalSyncProvider>
|
||||
</GlobalSDKProvider>
|
||||
<QueryProvider>
|
||||
<GlobalSDKProvider>
|
||||
<GlobalSyncProvider>
|
||||
<Dynamic
|
||||
component={props.router ?? Router}
|
||||
root={(routerProps) => <RouterRoot appChildren={props.children}>{routerProps.children}</RouterRoot>}
|
||||
>
|
||||
<Route path="/" component={HomeRoute} />
|
||||
<Route path="/:dir" component={DirectoryLayout}>
|
||||
<Route path="/" component={SessionIndexRoute} />
|
||||
<Route path="/session/:id?" component={SessionRoute} />
|
||||
</Route>
|
||||
</Dynamic>
|
||||
</GlobalSyncProvider>
|
||||
</GlobalSDKProvider>
|
||||
</QueryProvider>
|
||||
</ServerKey>
|
||||
</ConnectionGate>
|
||||
</ServerProvider>
|
||||
|
||||
@@ -327,7 +327,7 @@ export function DialogConnectProvider(props: { provider: string }) {
|
||||
if (loading()) return
|
||||
if (methods().length === 1) {
|
||||
auto = true
|
||||
selectMethod(0)
|
||||
void selectMethod(0)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -373,7 +373,7 @@ export function DialogConnectProvider(props: { provider: string }) {
|
||||
key={(m) => m?.label}
|
||||
onSelect={async (selected, index) => {
|
||||
if (!selected) return
|
||||
selectMethod(index)
|
||||
void selectMethod(index)
|
||||
}}
|
||||
>
|
||||
{(i) => (
|
||||
|
||||
@@ -12,6 +12,7 @@ import { type LocalProject, getAvatarColors } from "@/context/layout"
|
||||
import { getFilename } from "@opencode-ai/shared/util/path"
|
||||
import { Avatar } from "@opencode-ai/ui/avatar"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { getProjectAvatarSource } from "@/pages/layout/sidebar-items"
|
||||
|
||||
const AVATAR_COLOR_KEYS = ["pink", "mint", "orange", "purple", "cyan", "lime"] as const
|
||||
|
||||
@@ -26,8 +27,8 @@ export function DialogEditProject(props: { project: LocalProject }) {
|
||||
|
||||
const [store, setStore] = createStore({
|
||||
name: defaultName(),
|
||||
color: props.project.icon?.color || "pink",
|
||||
iconUrl: props.project.icon?.override || "",
|
||||
color: props.project.icon?.color,
|
||||
iconOverride: props.project.icon?.override,
|
||||
startup: props.project.commands?.start ?? "",
|
||||
dragOver: false,
|
||||
iconHover: false,
|
||||
@@ -39,7 +40,7 @@ export function DialogEditProject(props: { project: LocalProject }) {
|
||||
if (!file.type.startsWith("image/")) return
|
||||
const reader = new FileReader()
|
||||
reader.onload = (e) => {
|
||||
setStore("iconUrl", e.target?.result as string)
|
||||
setStore("iconOverride", e.target?.result as string)
|
||||
setStore("iconHover", false)
|
||||
}
|
||||
reader.readAsDataURL(file)
|
||||
@@ -68,7 +69,7 @@ export function DialogEditProject(props: { project: LocalProject }) {
|
||||
}
|
||||
|
||||
function clearIcon() {
|
||||
setStore("iconUrl", "")
|
||||
setStore("iconOverride", "")
|
||||
}
|
||||
|
||||
const saveMutation = useMutation(() => ({
|
||||
@@ -81,17 +82,17 @@ export function DialogEditProject(props: { project: LocalProject }) {
|
||||
projectID: props.project.id,
|
||||
directory: props.project.worktree,
|
||||
name,
|
||||
icon: { color: store.color, override: store.iconUrl },
|
||||
icon: { color: store.color || "", override: store.iconOverride || "" },
|
||||
commands: { start },
|
||||
})
|
||||
globalSync.project.icon(props.project.worktree, store.iconUrl || undefined)
|
||||
globalSync.project.icon(props.project.worktree, store.iconOverride || undefined)
|
||||
dialog.close()
|
||||
return
|
||||
}
|
||||
|
||||
globalSync.project.meta(props.project.worktree, {
|
||||
name,
|
||||
icon: { color: store.color, override: store.iconUrl || undefined },
|
||||
icon: { color: store.color || undefined, override: store.iconOverride || undefined },
|
||||
commands: { start: start || undefined },
|
||||
})
|
||||
dialog.close()
|
||||
@@ -130,13 +131,13 @@ export function DialogEditProject(props: { project: LocalProject }) {
|
||||
classList={{
|
||||
"border-text-interactive-base bg-surface-info-base/20": store.dragOver,
|
||||
"border-border-base hover:border-border-strong": !store.dragOver,
|
||||
"overflow-hidden": !!store.iconUrl,
|
||||
"overflow-hidden": !!store.iconOverride,
|
||||
}}
|
||||
onDrop={handleDrop}
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onClick={() => {
|
||||
if (store.iconUrl && store.iconHover) {
|
||||
if (store.iconOverride && store.iconHover) {
|
||||
clearIcon()
|
||||
} else {
|
||||
iconInput?.click()
|
||||
@@ -144,7 +145,11 @@ export function DialogEditProject(props: { project: LocalProject }) {
|
||||
}}
|
||||
>
|
||||
<Show
|
||||
when={store.iconUrl}
|
||||
when={getProjectAvatarSource(props.project.id, {
|
||||
color: store.color,
|
||||
url: props.project.icon?.url,
|
||||
override: store.iconOverride,
|
||||
})}
|
||||
fallback={
|
||||
<div class="size-full flex items-center justify-center">
|
||||
<Avatar
|
||||
@@ -155,18 +160,20 @@ export function DialogEditProject(props: { project: LocalProject }) {
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<img
|
||||
src={store.iconUrl}
|
||||
alt={language.t("dialog.project.edit.icon.alt")}
|
||||
class="size-full object-cover"
|
||||
/>
|
||||
{(src) => (
|
||||
<img
|
||||
src={src()}
|
||||
alt={language.t("dialog.project.edit.icon.alt")}
|
||||
class="size-full object-cover"
|
||||
/>
|
||||
)}
|
||||
</Show>
|
||||
</div>
|
||||
<div
|
||||
class="absolute inset-0 size-16 bg-surface-raised-stronger-non-alpha/90 rounded-[6px] z-10 pointer-events-none flex items-center justify-center transition-opacity"
|
||||
classList={{
|
||||
"opacity-100": store.iconHover && !store.iconUrl,
|
||||
"opacity-0": !(store.iconHover && !store.iconUrl),
|
||||
"opacity-100": store.iconHover && !store.iconOverride,
|
||||
"opacity-0": !(store.iconHover && !store.iconOverride),
|
||||
}}
|
||||
>
|
||||
<Icon name="cloud-upload" size="large" class="text-icon-on-interactive-base drop-shadow-sm" />
|
||||
@@ -174,8 +181,8 @@ export function DialogEditProject(props: { project: LocalProject }) {
|
||||
<div
|
||||
class="absolute inset-0 size-16 bg-surface-raised-stronger-non-alpha/90 rounded-[6px] z-10 pointer-events-none flex items-center justify-center transition-opacity"
|
||||
classList={{
|
||||
"opacity-100": store.iconHover && !!store.iconUrl,
|
||||
"opacity-0": !(store.iconHover && !!store.iconUrl),
|
||||
"opacity-100": store.iconHover && !!store.iconOverride,
|
||||
"opacity-0": !(store.iconHover && !!store.iconOverride),
|
||||
}}
|
||||
>
|
||||
<Icon name="trash" size="large" class="text-icon-on-interactive-base drop-shadow-sm" />
|
||||
@@ -198,7 +205,7 @@ export function DialogEditProject(props: { project: LocalProject }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Show when={!store.iconUrl}>
|
||||
<Show when={!store.iconOverride}>
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-12-medium text-text-weak">{language.t("dialog.project.edit.color")}</label>
|
||||
<div class="flex gap-1.5">
|
||||
@@ -215,7 +222,10 @@ export function DialogEditProject(props: { project: LocalProject }) {
|
||||
"bg-transparent border border-transparent hover:bg-surface-base-hover hover:border-border-weak-base":
|
||||
store.color !== color,
|
||||
}}
|
||||
onClick={() => setStore("color", color)}
|
||||
onClick={() => {
|
||||
if (store.color === color && !props.project.icon?.url) return
|
||||
setStore("color", store.color === color ? undefined : color)
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
fallback={store.name || defaultName()}
|
||||
|
||||
@@ -348,8 +348,8 @@ export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFil
|
||||
|
||||
const open = (path: string) => {
|
||||
const value = file.tab(path)
|
||||
tabs().open(value)
|
||||
file.load(path)
|
||||
void tabs().open(value)
|
||||
void file.load(path)
|
||||
if (!view().reviewPanel.opened()) view().reviewPanel.open()
|
||||
layout.fileTree.setTab("all")
|
||||
props.onOpenFile?.(path)
|
||||
|
||||
@@ -344,7 +344,7 @@ export function DialogSelectServer() {
|
||||
|
||||
createEffect(() => {
|
||||
items()
|
||||
refreshHealth()
|
||||
void refreshHealth()
|
||||
const interval = setInterval(refreshHealth, 10_000)
|
||||
onCleanup(() => clearInterval(interval))
|
||||
})
|
||||
@@ -498,13 +498,13 @@ export function DialogSelectServer() {
|
||||
async function handleRemove(url: ServerConnection.Key) {
|
||||
server.remove(url)
|
||||
if ((await platform.getDefaultServer?.()) === url) {
|
||||
platform.setDefaultServer?.(null)
|
||||
void platform.setDefaultServer?.(null)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog title={formTitle()}>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex flex-1 min-h-0 flex-col gap-2">
|
||||
<Show
|
||||
when={!isFormMode()}
|
||||
fallback={
|
||||
@@ -536,10 +536,10 @@ export function DialogSelectServer() {
|
||||
items={sortedItems}
|
||||
key={(x) => x.http.url}
|
||||
onSelect={(x) => {
|
||||
if (x) select(x)
|
||||
if (x) void select(x)
|
||||
}}
|
||||
divider={true}
|
||||
class="px-5 [&_[data-slot=list-search-wrapper]]:w-full [&_[data-slot=list-scroll]]h-[300px] [&_[data-slot=list-scroll]]:overflow-y-auto [&_[data-slot=list-items]]:bg-surface-base [&_[data-slot=list-items]]:rounded-md [&_[data-slot=list-item]]:min-h-14 [&_[data-slot=list-item]]:p-3 [&_[data-slot=list-item]]:!bg-transparent"
|
||||
class="flex-1 min-h-0 px-5 [&_[data-slot=list-search-wrapper]]:w-full [&_[data-slot=list-scroll]]:flex-1 [&_[data-slot=list-scroll]]:overflow-y-auto [&_[data-slot=list-items]]:bg-surface-base [&_[data-slot=list-items]]:rounded-md [&_[data-slot=list-item]]:min-h-14 [&_[data-slot=list-item]]:p-3 [&_[data-slot=list-item]]:!bg-transparent"
|
||||
>
|
||||
{(i) => {
|
||||
const key = ServerConnection.key(i)
|
||||
@@ -619,7 +619,7 @@ export function DialogSelectServer() {
|
||||
</List>
|
||||
</Show>
|
||||
|
||||
<div class="px-5 pb-5">
|
||||
<div class="shrink-0 px-5 pb-5">
|
||||
<Show
|
||||
when={isFormMode()}
|
||||
fallback={
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
Switch,
|
||||
untrack,
|
||||
type ComponentProps,
|
||||
type JSXElement,
|
||||
type ParentProps,
|
||||
} from "solid-js"
|
||||
import { Dynamic } from "solid-js/web"
|
||||
@@ -149,7 +148,7 @@ const FileTreeNode = (
|
||||
classList={{
|
||||
"w-full min-w-0 h-6 flex items-center justify-start gap-x-1.5 rounded-md px-1.5 py-0 text-left hover:bg-surface-raised-base-hover active:bg-surface-base-active transition-colors cursor-pointer": true,
|
||||
"bg-surface-base-active": local.node.path === local.active,
|
||||
...(local.classList ?? {}),
|
||||
...local.classList,
|
||||
[local.class ?? ""]: !!local.class,
|
||||
[local.nodeClass ?? ""]: !!local.nodeClass,
|
||||
}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useFilteredList } from "@opencode-ai/ui/hooks"
|
||||
import { useSpring } from "@opencode-ai/ui/motion-spring"
|
||||
import { createEffect, on, Component, Show, onCleanup, createMemo, createSignal } from "solid-js"
|
||||
import { createEffect, on, Component, Show, onCleanup, createMemo, createSignal, createResource } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { useLocal } from "@/context/local"
|
||||
import { selectionFromLines, type SelectedLineRange, useFile } from "@/context/file"
|
||||
@@ -54,6 +54,8 @@ import { PromptImageAttachments } from "./prompt-input/image-attachments"
|
||||
import { PromptDragOverlay } from "./prompt-input/drag-overlay"
|
||||
import { promptPlaceholder } from "./prompt-input/placeholder"
|
||||
import { ImagePreview } from "@opencode-ai/ui/image-preview"
|
||||
import { useQueries } from "@tanstack/solid-query"
|
||||
import { loadAgentsQuery, loadProvidersQuery } from "@/context/global-sync/bootstrap"
|
||||
|
||||
interface PromptInputProps {
|
||||
class?: string
|
||||
@@ -100,6 +102,7 @@ const NON_EMPTY_TEXT = /[^\s\u200B]/
|
||||
|
||||
export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
const sdk = useSDK()
|
||||
|
||||
const sync = useSync()
|
||||
const local = useLocal()
|
||||
const files = useFile()
|
||||
@@ -212,9 +215,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
if (!view().reviewPanel.opened()) view().reviewPanel.open()
|
||||
layout.fileTree.setTab("all")
|
||||
const tab = files.tab(item.path)
|
||||
tabs().open(tab)
|
||||
void tabs().open(tab)
|
||||
tabs().setActive(tab)
|
||||
Promise.resolve(files.load(item.path)).finally(() => queueCommentFocus())
|
||||
void Promise.resolve(files.load(item.path)).finally(() => queueCommentFocus())
|
||||
}
|
||||
|
||||
const recent = createMemo(() => {
|
||||
@@ -267,7 +270,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
const buttonsSpring = useSpring(() => (store.mode === "normal" ? 1 : 0), { visualDuration: 0.2, bounce: 0 })
|
||||
const motion = (value: number) => ({
|
||||
opacity: value,
|
||||
transform: `scale(${0.95 + value * 0.05})`,
|
||||
transform: `scale(${0.98 + value * 0.02})`,
|
||||
filter: `blur(${(1 - value) * 2}px)`,
|
||||
"pointer-events": value > 0.5 ? ("auto" as const) : ("none" as const),
|
||||
})
|
||||
@@ -342,7 +345,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
promptPlaceholder({
|
||||
mode: store.mode,
|
||||
commentCount: commentCount(),
|
||||
example: suggest() ? language.t(EXAMPLES[store.placeholder]) : "",
|
||||
example: suggest() ? (store.mode === "shell" ? "git status" : language.t(EXAMPLES[store.placeholder])) : "",
|
||||
suggest: suggest(),
|
||||
t: (key, params) => language.t(key as Parameters<typeof language.t>[0], params as never),
|
||||
}),
|
||||
@@ -1139,7 +1142,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
}
|
||||
|
||||
if (working()) {
|
||||
abort()
|
||||
void abort()
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
return
|
||||
@@ -1205,7 +1208,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
return
|
||||
}
|
||||
if (working()) {
|
||||
abort()
|
||||
void abort()
|
||||
event.preventDefault()
|
||||
}
|
||||
return
|
||||
@@ -1245,12 +1248,27 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
) {
|
||||
return
|
||||
}
|
||||
handleSubmit(event)
|
||||
void handleSubmit(event)
|
||||
}
|
||||
}
|
||||
|
||||
const [agentsQuery, globalProvidersQuery, providersQuery] = useQueries(() => ({
|
||||
queries: [loadAgentsQuery(sdk.directory), loadProvidersQuery(null), loadProvidersQuery(sdk.directory)],
|
||||
}))
|
||||
|
||||
const agentsLoading = () => agentsQuery.isLoading
|
||||
const agentsShouldFadeIn = createMemo((prev) => prev ?? agentsLoading())
|
||||
const providersLoading = () => agentsLoading() || providersQuery.isLoading || globalProvidersQuery.isLoading
|
||||
const providersShouldFadeIn = createMemo((prev) => prev ?? providersLoading())
|
||||
|
||||
const [promptReady] = createResource(
|
||||
() => prompt.ready().promise,
|
||||
(p) => p,
|
||||
)
|
||||
|
||||
return (
|
||||
<div class="relative size-full _max-h-[320px] flex flex-col gap-0">
|
||||
{(promptReady(), null)}
|
||||
<PromptPopover
|
||||
popover={store.popover}
|
||||
setSlashPopoverRef={(el) => (slashPopoverRef = el)}
|
||||
@@ -1347,15 +1365,13 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
}}
|
||||
style={{ "padding-bottom": space }}
|
||||
/>
|
||||
<Show when={!prompt.dirty()}>
|
||||
<div
|
||||
class="absolute top-0 inset-x-0 pl-3 pr-2 pt-2 text-14-regular text-text-weak pointer-events-none whitespace-nowrap truncate"
|
||||
classList={{ "font-mono!": store.mode === "shell" }}
|
||||
style={{ "padding-bottom": space }}
|
||||
>
|
||||
{placeholder()}
|
||||
</div>
|
||||
</Show>
|
||||
<div
|
||||
class="absolute top-0 inset-x-0 pl-3 pr-2 pt-2 text-14-regular text-text-weak pointer-events-none whitespace-nowrap truncate"
|
||||
classList={{ "font-mono!": store.mode === "shell" }}
|
||||
style={{ "padding-bottom": space, display: prompt.dirty() ? "none" : undefined }}
|
||||
>
|
||||
{placeholder()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -1387,12 +1403,11 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
<IconButton
|
||||
data-action="prompt-submit"
|
||||
type="submit"
|
||||
disabled={store.mode !== "normal" || (!working() && blank())}
|
||||
disabled={!working() && blank()}
|
||||
tabIndex={store.mode === "normal" ? undefined : -1}
|
||||
icon={stopping() ? "stop" : "arrow-up"}
|
||||
icon={stopping() ? "stop" : store.mode === "shell" ? "arrow-undo-down" : "arrow-up"}
|
||||
variant="primary"
|
||||
class="size-8"
|
||||
style={buttons()}
|
||||
aria-label={stopping() ? language.t("prompt.action.stop") : language.t("prompt.action.send")}
|
||||
/>
|
||||
</Tooltip>
|
||||
@@ -1435,62 +1450,114 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
<div class="px-1.75 pt-5.5 pb-2 flex items-center gap-2 min-w-0">
|
||||
<div class="flex items-center gap-1.5 min-w-0 flex-1 relative">
|
||||
<div
|
||||
class="h-7 flex items-center gap-1.5 max-w-[160px] min-w-0 absolute inset-y-0 left-0"
|
||||
class="h-7 flex items-center gap-1.5 min-w-0 absolute inset-0"
|
||||
style={{
|
||||
padding: "0 4px 0 8px",
|
||||
padding: "0 0px 0 8px",
|
||||
...shell(),
|
||||
}}
|
||||
>
|
||||
<span class="truncate text-13-medium text-text-strong">{language.t("prompt.mode.shell")}</span>
|
||||
<div class="size-4 shrink-0" />
|
||||
<Icon name="console" />
|
||||
<span class="truncate text-13-medium text-text-base">{language.t("prompt.mode.shell")}</span>
|
||||
<div class="flex-1" />
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="text-text-base"
|
||||
onClick={() => {
|
||||
setStore("mode", "normal")
|
||||
}}
|
||||
>
|
||||
{language.t("common.cancel")}
|
||||
</Button>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 min-w-0 flex-1">
|
||||
<div data-component="prompt-agent-control">
|
||||
<TooltipKeybind
|
||||
placement="top"
|
||||
gutter={4}
|
||||
title={language.t("command.agent.cycle")}
|
||||
keybind={command.keybind("agent.cycle")}
|
||||
<div class="flex items-center gap-1.5 min-w-0 flex-1 h-7">
|
||||
<Show when={!agentsLoading()}>
|
||||
<div
|
||||
data-component="prompt-agent-control"
|
||||
style={agentsShouldFadeIn() ? { animation: "fade-in 0.3s" } : undefined}
|
||||
>
|
||||
<Select
|
||||
size="normal"
|
||||
options={agentNames()}
|
||||
current={local.agent.current()?.name ?? ""}
|
||||
onSelect={(value) => {
|
||||
local.agent.set(value)
|
||||
restoreFocus()
|
||||
}}
|
||||
class="capitalize max-w-[160px] text-text-base"
|
||||
valueClass="truncate text-13-regular text-text-base"
|
||||
triggerStyle={control()}
|
||||
triggerProps={{ "data-action": "prompt-agent" }}
|
||||
variant="ghost"
|
||||
/>
|
||||
</TooltipKeybind>
|
||||
</div>
|
||||
<Show when={store.mode !== "shell"}>
|
||||
<div data-component="prompt-model-control">
|
||||
<Show
|
||||
when={providers.paid().length > 0}
|
||||
fallback={
|
||||
<TooltipKeybind
|
||||
placement="top"
|
||||
gutter={4}
|
||||
title={language.t("command.agent.cycle")}
|
||||
keybind={command.keybind("agent.cycle")}
|
||||
>
|
||||
<Select
|
||||
size="normal"
|
||||
options={agentNames()}
|
||||
current={local.agent.current()?.name ?? ""}
|
||||
onSelect={(value) => {
|
||||
local.agent.set(value)
|
||||
restoreFocus()
|
||||
}}
|
||||
class="capitalize max-w-[160px] text-text-base"
|
||||
valueClass="truncate text-13-regular text-text-base"
|
||||
triggerStyle={control()}
|
||||
triggerProps={{ "data-action": "prompt-agent" }}
|
||||
variant="ghost"
|
||||
/>
|
||||
</TooltipKeybind>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={!providersLoading()}>
|
||||
<Show when={store.mode !== "shell"}>
|
||||
<div
|
||||
data-component="prompt-model-control"
|
||||
style={providersShouldFadeIn() ? { animation: "fade-in 0.3s" } : undefined}
|
||||
>
|
||||
<Show
|
||||
when={providers.paid().length > 0}
|
||||
fallback={
|
||||
<TooltipKeybind
|
||||
placement="top"
|
||||
gutter={4}
|
||||
title={language.t("command.model.choose")}
|
||||
keybind={command.keybind("model.choose")}
|
||||
>
|
||||
<Button
|
||||
data-action="prompt-model"
|
||||
as="div"
|
||||
variant="ghost"
|
||||
size="normal"
|
||||
class="min-w-0 max-w-[320px] text-13-regular text-text-base group"
|
||||
style={control()}
|
||||
onClick={() => {
|
||||
void import("@/components/dialog-select-model-unpaid").then((x) => {
|
||||
dialog.show(() => <x.DialogSelectModelUnpaid model={local.model} />)
|
||||
})
|
||||
}}
|
||||
>
|
||||
<Show when={local.model.current()?.provider?.id}>
|
||||
<ProviderIcon
|
||||
id={local.model.current()?.provider?.id ?? ""}
|
||||
class="size-4 shrink-0 opacity-40 group-hover:opacity-100 transition-opacity duration-150"
|
||||
style={{ "will-change": "opacity", transform: "translateZ(0)" }}
|
||||
/>
|
||||
</Show>
|
||||
<span class="truncate">
|
||||
{local.model.current()?.name ?? language.t("dialog.model.select.title")}
|
||||
</span>
|
||||
<Icon name="chevron-down" size="small" class="shrink-0" />
|
||||
</Button>
|
||||
</TooltipKeybind>
|
||||
}
|
||||
>
|
||||
<TooltipKeybind
|
||||
placement="top"
|
||||
gutter={4}
|
||||
title={language.t("command.model.choose")}
|
||||
keybind={command.keybind("model.choose")}
|
||||
>
|
||||
<Button
|
||||
data-action="prompt-model"
|
||||
as="div"
|
||||
variant="ghost"
|
||||
size="normal"
|
||||
class="min-w-0 max-w-[320px] text-13-regular text-text-base group"
|
||||
style={control()}
|
||||
onClick={() => {
|
||||
void import("@/components/dialog-select-model-unpaid").then((x) => {
|
||||
dialog.show(() => <x.DialogSelectModelUnpaid model={local.model} />)
|
||||
})
|
||||
<ModelSelectorPopover
|
||||
model={local.model}
|
||||
triggerAs={Button}
|
||||
triggerProps={{
|
||||
variant: "ghost",
|
||||
size: "normal",
|
||||
style: control(),
|
||||
class: "min-w-0 max-w-[320px] text-13-regular text-text-base group",
|
||||
"data-action": "prompt-model",
|
||||
}}
|
||||
onClose={restoreFocus}
|
||||
>
|
||||
<Show when={local.model.current()?.provider?.id}>
|
||||
<ProviderIcon
|
||||
@@ -1503,67 +1570,40 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
{local.model.current()?.name ?? language.t("dialog.model.select.title")}
|
||||
</span>
|
||||
<Icon name="chevron-down" size="small" class="shrink-0" />
|
||||
</Button>
|
||||
</ModelSelectorPopover>
|
||||
</TooltipKeybind>
|
||||
}
|
||||
>
|
||||
<TooltipKeybind
|
||||
placement="top"
|
||||
gutter={4}
|
||||
title={language.t("command.model.choose")}
|
||||
keybind={command.keybind("model.choose")}
|
||||
</Show>
|
||||
</div>
|
||||
<Show when={variants().length > 2}>
|
||||
<div
|
||||
data-component="prompt-variant-control"
|
||||
style={providersShouldFadeIn() ? { animation: "fade-in 0.3s" } : undefined}
|
||||
>
|
||||
<ModelSelectorPopover
|
||||
model={local.model}
|
||||
triggerAs={Button}
|
||||
triggerProps={{
|
||||
variant: "ghost",
|
||||
size: "normal",
|
||||
style: control(),
|
||||
class: "min-w-0 max-w-[320px] text-13-regular text-text-base group",
|
||||
"data-action": "prompt-model",
|
||||
}}
|
||||
onClose={restoreFocus}
|
||||
<TooltipKeybind
|
||||
placement="top"
|
||||
gutter={4}
|
||||
title={language.t("command.model.variant.cycle")}
|
||||
keybind={command.keybind("model.variant.cycle")}
|
||||
>
|
||||
<Show when={local.model.current()?.provider?.id}>
|
||||
<ProviderIcon
|
||||
id={local.model.current()?.provider?.id ?? ""}
|
||||
class="size-4 shrink-0 opacity-40 group-hover:opacity-100 transition-opacity duration-150"
|
||||
style={{ "will-change": "opacity", transform: "translateZ(0)" }}
|
||||
/>
|
||||
</Show>
|
||||
<span class="truncate">
|
||||
{local.model.current()?.name ?? language.t("dialog.model.select.title")}
|
||||
</span>
|
||||
<Icon name="chevron-down" size="small" class="shrink-0" />
|
||||
</ModelSelectorPopover>
|
||||
</TooltipKeybind>
|
||||
<Select
|
||||
size="normal"
|
||||
options={variants()}
|
||||
current={local.model.variant.current() ?? "default"}
|
||||
label={(x) => (x === "default" ? language.t("common.default") : x)}
|
||||
onSelect={(value) => {
|
||||
local.model.variant.set(value === "default" ? undefined : value)
|
||||
restoreFocus()
|
||||
}}
|
||||
class="capitalize max-w-[160px] text-text-base"
|
||||
valueClass="truncate text-13-regular text-text-base"
|
||||
triggerStyle={control()}
|
||||
triggerProps={{ "data-action": "prompt-model-variant" }}
|
||||
variant="ghost"
|
||||
/>
|
||||
</TooltipKeybind>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
<div data-component="prompt-variant-control">
|
||||
<TooltipKeybind
|
||||
placement="top"
|
||||
gutter={4}
|
||||
title={language.t("command.model.variant.cycle")}
|
||||
keybind={command.keybind("model.variant.cycle")}
|
||||
>
|
||||
<Select
|
||||
size="normal"
|
||||
options={variants()}
|
||||
current={local.model.variant.current() ?? "default"}
|
||||
label={(x) => (x === "default" ? language.t("common.default") : x)}
|
||||
onSelect={(value) => {
|
||||
local.model.variant.set(value === "default" ? undefined : value)
|
||||
restoreFocus()
|
||||
}}
|
||||
class="capitalize max-w-[160px] text-text-base"
|
||||
valueClass="truncate text-13-regular text-text-base"
|
||||
triggerStyle={control()}
|
||||
triggerProps={{ "data-action": "prompt-model-variant" }}
|
||||
variant="ghost"
|
||||
/>
|
||||
</TooltipKeybind>
|
||||
</div>
|
||||
</Show>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@ describe("promptPlaceholder", () => {
|
||||
suggest: true,
|
||||
t,
|
||||
})
|
||||
expect(value).toBe("prompt.placeholder.shell")
|
||||
expect(value).toBe("prompt.placeholder.shell:example")
|
||||
})
|
||||
|
||||
test("returns summarize placeholders for comment context", () => {
|
||||
|
||||
@@ -7,7 +7,7 @@ type PromptPlaceholderInput = {
|
||||
}
|
||||
|
||||
export function promptPlaceholder(input: PromptPlaceholderInput) {
|
||||
if (input.mode === "shell") return input.t("prompt.placeholder.shell")
|
||||
if (input.mode === "shell") return input.t("prompt.placeholder.shell", { example: input.example })
|
||||
if (input.commentCount > 1) return input.t("prompt.placeholder.summarizeComments")
|
||||
if (input.commentCount === 1) return input.t("prompt.placeholder.summarizeComment")
|
||||
if (!input.suggest) return input.t("prompt.placeholder.simple")
|
||||
|
||||
@@ -295,7 +295,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
|
||||
const mode = input.mode()
|
||||
|
||||
if (text.trim().length === 0 && images.length === 0 && input.commentCount() === 0) {
|
||||
if (input.working()) abort()
|
||||
if (input.working()) void abort()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ function openSessionContext(args: {
|
||||
}) {
|
||||
if (!args.view.reviewPanel.opened()) args.view.reviewPanel.open()
|
||||
if (args.layout.fileTree.opened() && args.layout.fileTree.tab() !== "all") args.layout.fileTree.setTab("all")
|
||||
args.tabs.open("context")
|
||||
void args.tabs.open("context")
|
||||
args.tabs.setActive("context")
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Spinner } from "@opencode-ai/ui/spinner"
|
||||
import { showToast } from "@opencode-ai/ui/toast"
|
||||
import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip"
|
||||
import { getFilename } from "@opencode-ai/shared/util/path"
|
||||
import { createEffect, createMemo, For, onCleanup, Show } from "solid-js"
|
||||
import { createEffect, createMemo, createSignal, For, onMount, Show } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { Portal } from "solid-js/web"
|
||||
import { useCommand } from "@/context/command"
|
||||
@@ -16,6 +16,7 @@ import { useLanguage } from "@/context/language"
|
||||
import { useLayout } from "@/context/layout"
|
||||
import { usePlatform } from "@/context/platform"
|
||||
import { useServer } from "@/context/server"
|
||||
import { useSettings } from "@/context/settings"
|
||||
import { useSync } from "@/context/sync"
|
||||
import { useTerminal } from "@/context/terminal"
|
||||
import { focusTerminalById } from "@/pages/session/helpers"
|
||||
@@ -134,6 +135,7 @@ export function SessionHeader() {
|
||||
const server = useServer()
|
||||
const platform = usePlatform()
|
||||
const language = useLanguage()
|
||||
const settings = useSettings()
|
||||
const sync = useSync()
|
||||
const terminal = useTerminal()
|
||||
const { params, view } = useSessionLayout()
|
||||
@@ -151,6 +153,11 @@ export function SessionHeader() {
|
||||
})
|
||||
const hotkey = createMemo(() => command.keybind("file.open"))
|
||||
const os = createMemo(() => detectOS(platform))
|
||||
const isDesktopBeta = platform.platform === "desktop" && import.meta.env.VITE_OPENCODE_CHANNEL === "beta"
|
||||
const search = createMemo(() => !isDesktopBeta || settings.general.showSearch())
|
||||
const tree = createMemo(() => !isDesktopBeta || settings.general.showFileTree())
|
||||
const term = createMemo(() => !isDesktopBeta || settings.general.showTerminal())
|
||||
const status = createMemo(() => !isDesktopBeta || settings.general.showStatus())
|
||||
|
||||
const [exists, setExists] = createStore<Partial<Record<OpenApp, boolean>>>({
|
||||
finder: true,
|
||||
@@ -262,12 +269,16 @@ export function SessionHeader() {
|
||||
.catch((err: unknown) => showRequestError(language, err))
|
||||
}
|
||||
|
||||
const centerMount = createMemo(() => document.getElementById("opencode-titlebar-center"))
|
||||
const rightMount = createMemo(() => document.getElementById("opencode-titlebar-right"))
|
||||
const [centerMount, setCenterMount] = createSignal<HTMLElement | null>(null)
|
||||
const [rightMount, setRightMount] = createSignal<HTMLElement | null>(null)
|
||||
onMount(() => {
|
||||
setCenterMount(document.getElementById("opencode-titlebar-center"))
|
||||
setRightMount(document.getElementById("opencode-titlebar-right"))
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<Show when={centerMount()}>
|
||||
<Show when={search() && centerMount()}>
|
||||
{(mount) => (
|
||||
<Portal mount={mount()}>
|
||||
<Button
|
||||
@@ -415,24 +426,28 @@ export function SessionHeader() {
|
||||
</div>
|
||||
</Show>
|
||||
<div class="flex items-center gap-1">
|
||||
<Tooltip placement="bottom" value={language.t("status.popover.trigger")}>
|
||||
<StatusPopover />
|
||||
</Tooltip>
|
||||
<TooltipKeybind
|
||||
title={language.t("command.terminal.toggle")}
|
||||
keybind={command.keybind("terminal.toggle")}
|
||||
>
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="group/terminal-toggle titlebar-icon w-8 h-6 p-0 box-border shrink-0"
|
||||
onClick={toggleTerminal}
|
||||
aria-label={language.t("command.terminal.toggle")}
|
||||
aria-expanded={view().terminal.opened()}
|
||||
aria-controls="terminal-panel"
|
||||
<Show when={status()}>
|
||||
<Tooltip placement="bottom" value={language.t("status.popover.trigger")}>
|
||||
<StatusPopover />
|
||||
</Tooltip>
|
||||
</Show>
|
||||
<Show when={term()}>
|
||||
<TooltipKeybind
|
||||
title={language.t("command.terminal.toggle")}
|
||||
keybind={command.keybind("terminal.toggle")}
|
||||
>
|
||||
<Icon size="small" name={view().terminal.opened() ? "terminal-active" : "terminal"} />
|
||||
</Button>
|
||||
</TooltipKeybind>
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="group/terminal-toggle titlebar-icon w-8 h-6 p-0 box-border shrink-0"
|
||||
onClick={toggleTerminal}
|
||||
aria-label={language.t("command.terminal.toggle")}
|
||||
aria-expanded={view().terminal.opened()}
|
||||
aria-controls="terminal-panel"
|
||||
>
|
||||
<Icon size="small" name={view().terminal.opened() ? "terminal-active" : "terminal"} />
|
||||
</Button>
|
||||
</TooltipKeybind>
|
||||
</Show>
|
||||
|
||||
<div class="hidden md:flex items-center gap-1 shrink-0">
|
||||
<TooltipKeybind
|
||||
@@ -451,30 +466,32 @@ export function SessionHeader() {
|
||||
</Button>
|
||||
</TooltipKeybind>
|
||||
|
||||
<TooltipKeybind
|
||||
title={language.t("command.fileTree.toggle")}
|
||||
keybind={command.keybind("fileTree.toggle")}
|
||||
>
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="titlebar-icon w-8 h-6 p-0 box-border"
|
||||
onClick={() => layout.fileTree.toggle()}
|
||||
aria-label={language.t("command.fileTree.toggle")}
|
||||
aria-expanded={layout.fileTree.opened()}
|
||||
aria-controls="file-tree-panel"
|
||||
<Show when={tree()}>
|
||||
<TooltipKeybind
|
||||
title={language.t("command.fileTree.toggle")}
|
||||
keybind={command.keybind("fileTree.toggle")}
|
||||
>
|
||||
<div class="relative flex items-center justify-center size-4">
|
||||
<Icon
|
||||
size="small"
|
||||
name={layout.fileTree.opened() ? "file-tree-active" : "file-tree"}
|
||||
classList={{
|
||||
"text-icon-strong": layout.fileTree.opened(),
|
||||
"text-icon-weak": !layout.fileTree.opened(),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Button>
|
||||
</TooltipKeybind>
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="titlebar-icon w-8 h-6 p-0 box-border"
|
||||
onClick={() => layout.fileTree.toggle()}
|
||||
aria-label={language.t("command.fileTree.toggle")}
|
||||
aria-expanded={layout.fileTree.opened()}
|
||||
aria-controls="file-tree-panel"
|
||||
>
|
||||
<div class="relative flex items-center justify-center size-4">
|
||||
<Icon
|
||||
size="small"
|
||||
name={layout.fileTree.opened() ? "file-tree-active" : "file-tree"}
|
||||
classList={{
|
||||
"text-icon-strong": layout.fileTree.opened(),
|
||||
"text-icon-weak": !layout.fileTree.opened(),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Button>
|
||||
</TooltipKeybind>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -44,7 +44,7 @@ export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () =>
|
||||
|
||||
const close = () => {
|
||||
const count = terminal.all().length
|
||||
terminal.close(props.terminal.id)
|
||||
void terminal.close(props.terminal.id)
|
||||
if (count === 1) {
|
||||
props.onClose?.()
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ import {
|
||||
sansDefault,
|
||||
sansFontFamily,
|
||||
sansInput,
|
||||
terminalDefault,
|
||||
terminalFontFamily,
|
||||
terminalInput,
|
||||
useSettings,
|
||||
} from "@/context/settings"
|
||||
import { decode64 } from "@/utils/base64"
|
||||
@@ -106,6 +109,7 @@ export const SettingsGeneral: Component = () => {
|
||||
|
||||
permission.disableAutoAccept(params.id, value)
|
||||
}
|
||||
const desktop = createMemo(() => platform.platform === "desktop")
|
||||
|
||||
const check = () => {
|
||||
if (!platform.checkUpdate) return
|
||||
@@ -124,27 +128,25 @@ export const SettingsGeneral: Component = () => {
|
||||
return
|
||||
}
|
||||
|
||||
const actions =
|
||||
platform.update && platform.restart
|
||||
? [
|
||||
{
|
||||
label: language.t("toast.update.action.installRestart"),
|
||||
onClick: async () => {
|
||||
await platform.update!()
|
||||
await platform.restart!()
|
||||
},
|
||||
const actions = platform.updateAndRestart
|
||||
? [
|
||||
{
|
||||
label: language.t("toast.update.action.installRestart"),
|
||||
onClick: async () => {
|
||||
await platform.updateAndRestart!()
|
||||
},
|
||||
{
|
||||
label: language.t("toast.update.action.notYet"),
|
||||
onClick: "dismiss" as const,
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
label: language.t("toast.update.action.notYet"),
|
||||
onClick: "dismiss" as const,
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: language.t("toast.update.action.notYet"),
|
||||
onClick: "dismiss" as const,
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
label: language.t("toast.update.action.notYet"),
|
||||
onClick: "dismiss" as const,
|
||||
},
|
||||
]
|
||||
|
||||
showToast({
|
||||
persistent: true,
|
||||
@@ -180,6 +182,7 @@ export const SettingsGeneral: Component = () => {
|
||||
const soundOptions = [noneSound, ...SOUND_OPTIONS]
|
||||
const mono = () => monoInput(settings.appearance.font())
|
||||
const sans = () => sansInput(settings.appearance.uiFont())
|
||||
const terminal = () => terminalInput(settings.appearance.terminalFont())
|
||||
|
||||
const soundSelectProps = (
|
||||
enabled: () => boolean,
|
||||
@@ -275,6 +278,86 @@ export const SettingsGeneral: Component = () => {
|
||||
/>
|
||||
</div>
|
||||
</SettingsRow>
|
||||
|
||||
<SettingsRow
|
||||
title={language.t("settings.general.row.showSessionProgressBar.title")}
|
||||
description={language.t("settings.general.row.showSessionProgressBar.description")}
|
||||
>
|
||||
<div data-action="settings-show-session-progress-bar">
|
||||
<Switch
|
||||
checked={settings.general.showSessionProgressBar()}
|
||||
onChange={(checked) => settings.general.setShowSessionProgressBar(checked)}
|
||||
/>
|
||||
</div>
|
||||
</SettingsRow>
|
||||
</SettingsList>
|
||||
</div>
|
||||
)
|
||||
|
||||
const AdvancedSection = () => (
|
||||
<div class="flex flex-col gap-1">
|
||||
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.advanced")}</h3>
|
||||
|
||||
<SettingsList>
|
||||
<SettingsRow
|
||||
title={language.t("settings.general.row.showFileTree.title")}
|
||||
description={language.t("settings.general.row.showFileTree.description")}
|
||||
>
|
||||
<div data-action="settings-show-file-tree">
|
||||
<Switch
|
||||
checked={settings.general.showFileTree()}
|
||||
onChange={(checked) => settings.general.setShowFileTree(checked)}
|
||||
/>
|
||||
</div>
|
||||
</SettingsRow>
|
||||
|
||||
<SettingsRow
|
||||
title={language.t("settings.general.row.showNavigation.title")}
|
||||
description={language.t("settings.general.row.showNavigation.description")}
|
||||
>
|
||||
<div data-action="settings-show-navigation">
|
||||
<Switch
|
||||
checked={settings.general.showNavigation()}
|
||||
onChange={(checked) => settings.general.setShowNavigation(checked)}
|
||||
/>
|
||||
</div>
|
||||
</SettingsRow>
|
||||
|
||||
<SettingsRow
|
||||
title={language.t("settings.general.row.showSearch.title")}
|
||||
description={language.t("settings.general.row.showSearch.description")}
|
||||
>
|
||||
<div data-action="settings-show-search">
|
||||
<Switch
|
||||
checked={settings.general.showSearch()}
|
||||
onChange={(checked) => settings.general.setShowSearch(checked)}
|
||||
/>
|
||||
</div>
|
||||
</SettingsRow>
|
||||
|
||||
<SettingsRow
|
||||
title={language.t("settings.general.row.showTerminal.title")}
|
||||
description={language.t("settings.general.row.showTerminal.description")}
|
||||
>
|
||||
<div data-action="settings-show-terminal">
|
||||
<Switch
|
||||
checked={settings.general.showTerminal()}
|
||||
onChange={(checked) => settings.general.setShowTerminal(checked)}
|
||||
/>
|
||||
</div>
|
||||
</SettingsRow>
|
||||
|
||||
<SettingsRow
|
||||
title={language.t("settings.general.row.showStatus.title")}
|
||||
description={language.t("settings.general.row.showStatus.description")}
|
||||
>
|
||||
<div data-action="settings-show-status">
|
||||
<Switch
|
||||
checked={settings.general.showStatus()}
|
||||
onChange={(checked) => settings.general.setShowStatus(checked)}
|
||||
/>
|
||||
</div>
|
||||
</SettingsRow>
|
||||
</SettingsList>
|
||||
</div>
|
||||
)
|
||||
@@ -382,6 +465,29 @@ export const SettingsGeneral: Component = () => {
|
||||
/>
|
||||
</div>
|
||||
</SettingsRow>
|
||||
|
||||
<SettingsRow
|
||||
title={language.t("settings.general.row.terminalFont.title")}
|
||||
description={language.t("settings.general.row.terminalFont.description")}
|
||||
>
|
||||
<div class="w-full sm:w-[220px]">
|
||||
<TextField
|
||||
data-action="settings-terminal-font"
|
||||
label={language.t("settings.general.row.terminalFont.title")}
|
||||
hideLabel
|
||||
type="text"
|
||||
value={terminal()}
|
||||
onChange={(value) => settings.appearance.setTerminalFont(value)}
|
||||
placeholder={terminalDefault}
|
||||
spellcheck={false}
|
||||
autocorrect="off"
|
||||
autocomplete="off"
|
||||
autocapitalize="off"
|
||||
class="text-12-regular"
|
||||
style={{ "font-family": terminalFontFamily(settings.appearance.terminalFont()) }}
|
||||
/>
|
||||
</div>
|
||||
</SettingsRow>
|
||||
</SettingsList>
|
||||
</div>
|
||||
)
|
||||
@@ -527,6 +633,7 @@ export const SettingsGeneral: Component = () => {
|
||||
</div>
|
||||
)
|
||||
|
||||
console.log(import.meta.env)
|
||||
return (
|
||||
<div class="flex flex-col h-full overflow-y-auto no-scrollbar px-4 pb-10 sm:px-10 sm:pb-10">
|
||||
<div class="sticky top-0 z-10 bg-[linear-gradient(to_bottom,var(--surface-stronger-non-alpha)_calc(100%_-_24px),transparent)]">
|
||||
@@ -609,6 +716,10 @@ export const SettingsGeneral: Component = () => {
|
||||
)
|
||||
}}
|
||||
</Show>
|
||||
|
||||
<Show when={desktop() && import.meta.env.VITE_OPENCODE_CHANNEL === "beta"}>
|
||||
<AdvancedSection />
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useLanguage } from "@/context/language"
|
||||
import { usePlatform } from "@/context/platform"
|
||||
import { useSDK } from "@/context/sdk"
|
||||
import { useServer } from "@/context/server"
|
||||
import { monoFontFamily, useSettings } from "@/context/settings"
|
||||
import { terminalFontFamily, useSettings } from "@/context/settings"
|
||||
import type { LocalPTY } from "@/context/terminal"
|
||||
import { disposeIfDisposable, getHoveredLinkText, setOptionIfSupported } from "@/utils/runtime-adapters"
|
||||
import { terminalWriter } from "@/utils/terminal-writer"
|
||||
@@ -191,7 +191,7 @@ export const Terminal = (props: TerminalProps) => {
|
||||
const scrollY = typeof local.pty.scrollY === "number" ? local.pty.scrollY : undefined
|
||||
let ws: WebSocket | undefined
|
||||
let term: Term | undefined
|
||||
let ghostty: Ghostty
|
||||
let _ghostty: Ghostty
|
||||
let serializeAddon: SerializeAddon
|
||||
let fitAddon: FitAddon
|
||||
let handleResize: () => void
|
||||
@@ -300,7 +300,7 @@ export const Terminal = (props: TerminalProps) => {
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
const font = monoFontFamily(settings.appearance.font())
|
||||
const font = terminalFontFamily(settings.appearance.terminalFont())
|
||||
if (!term) return
|
||||
setOptionIfSupported(term, "fontFamily", font)
|
||||
scheduleFit()
|
||||
@@ -360,7 +360,7 @@ export const Terminal = (props: TerminalProps) => {
|
||||
cols: restoreSize?.cols,
|
||||
rows: restoreSize?.rows,
|
||||
fontSize: 14,
|
||||
fontFamily: monoFontFamily(settings.appearance.font()),
|
||||
fontFamily: terminalFontFamily(settings.appearance.terminalFont()),
|
||||
allowTransparency: false,
|
||||
convertEol: false,
|
||||
theme: terminalColors(),
|
||||
@@ -372,7 +372,7 @@ export const Terminal = (props: TerminalProps) => {
|
||||
cleanup()
|
||||
return
|
||||
}
|
||||
ghostty = g
|
||||
_ghostty = g
|
||||
term = t
|
||||
output = terminalWriter((data, done) =>
|
||||
t.write(data, () => {
|
||||
@@ -415,7 +415,7 @@ export const Terminal = (props: TerminalProps) => {
|
||||
if (local.autoFocus !== false) focusTerminal()
|
||||
|
||||
if (typeof document !== "undefined" && document.fonts) {
|
||||
document.fonts.ready.then(scheduleFit)
|
||||
void document.fonts.ready.then(scheduleFit)
|
||||
}
|
||||
|
||||
const onResize = t.onResize((size) => {
|
||||
@@ -634,7 +634,7 @@ export const Terminal = (props: TerminalProps) => {
|
||||
tabIndex={-1}
|
||||
style={{ "background-color": terminalColors().background }}
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
...local.classList,
|
||||
"select-text": true,
|
||||
"size-full px-6 py-3 font-mono relative overflow-hidden": true,
|
||||
[local.class ?? ""]: !!local.class,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createEffect, createMemo, onCleanup, Show, untrack } from "solid-js"
|
||||
import { createEffect, createMemo, Show, untrack } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { useLocation, useNavigate, useParams } from "@solidjs/router"
|
||||
import { IconButton } from "@opencode-ai/ui/icon-button"
|
||||
@@ -11,6 +11,7 @@ import { useLayout } from "@/context/layout"
|
||||
import { usePlatform } from "@/context/platform"
|
||||
import { useCommand } from "@/context/command"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { useSettings } from "@/context/settings"
|
||||
import { applyPath, backPath, forwardPath } from "./titlebar-history"
|
||||
|
||||
type TauriDesktopWindow = {
|
||||
@@ -40,6 +41,7 @@ export function Titlebar() {
|
||||
const platform = usePlatform()
|
||||
const command = useCommand()
|
||||
const language = useLanguage()
|
||||
const settings = useSettings()
|
||||
const theme = useTheme()
|
||||
const navigate = useNavigate()
|
||||
const location = useLocation()
|
||||
@@ -78,6 +80,7 @@ export function Titlebar() {
|
||||
const canBack = createMemo(() => history.index > 0)
|
||||
const canForward = createMemo(() => history.index < history.stack.length - 1)
|
||||
const hasProjects = createMemo(() => layout.projects.list().length > 0)
|
||||
const nav = createMemo(() => import.meta.env.VITE_OPENCODE_CHANNEL !== "beta" || settings.general.showNavigation())
|
||||
|
||||
const back = () => {
|
||||
const next = backPath(history)
|
||||
@@ -252,41 +255,47 @@ export function Titlebar() {
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={hasProjects()}>
|
||||
<div
|
||||
class="flex items-center gap-0 transition-transform"
|
||||
classList={{
|
||||
"translate-x-0": !layout.sidebar.opened(),
|
||||
"-translate-x-[36px]": layout.sidebar.opened(),
|
||||
"duration-180 ease-out": !layout.sidebar.opened(),
|
||||
"duration-180 ease-in": layout.sidebar.opened(),
|
||||
}}
|
||||
>
|
||||
<Tooltip placement="bottom" value={language.t("common.goBack")} openDelay={2000}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
icon="chevron-left"
|
||||
class="titlebar-icon w-6 h-6 p-0 box-border"
|
||||
disabled={!canBack()}
|
||||
onClick={back}
|
||||
aria-label={language.t("common.goBack")}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip placement="bottom" value={language.t("common.goForward")} openDelay={2000}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
icon="chevron-right"
|
||||
class="titlebar-icon w-6 h-6 p-0 box-border"
|
||||
disabled={!canForward()}
|
||||
onClick={forward}
|
||||
aria-label={language.t("common.goForward")}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Show>
|
||||
<div
|
||||
class="flex items-center shrink-0"
|
||||
classList={{
|
||||
"-translate-x-[36px]": layout.sidebar.opened() && !!params.dir,
|
||||
"duration-180 ease-out": !layout.sidebar.opened(),
|
||||
"duration-180 ease-in": layout.sidebar.opened(),
|
||||
}}
|
||||
>
|
||||
<Show when={hasProjects() && nav()}>
|
||||
<div class="flex items-center gap-0 transition-transform">
|
||||
<Tooltip placement="bottom" value={language.t("common.goBack")} openDelay={2000}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
icon="chevron-left"
|
||||
class="titlebar-icon w-6 h-6 p-0 box-border"
|
||||
disabled={!canBack()}
|
||||
onClick={back}
|
||||
aria-label={language.t("common.goBack")}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip placement="bottom" value={language.t("common.goForward")} openDelay={2000}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
icon="chevron-right"
|
||||
class="titlebar-icon w-6 h-6 p-0 box-border"
|
||||
disabled={!canForward()}
|
||||
onClick={forward}
|
||||
aria-label={language.t("common.goForward")}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Show>
|
||||
<div id="opencode-titlebar-left" class="flex items-center gap-3 min-w-0 px-2" />
|
||||
{["beta", "dev"].includes(import.meta.env.VITE_OPENCODE_CHANNEL) && (
|
||||
<div class="bg-icon-interactive-base text-[#FFF] font-medium px-2 rounded-sm uppercase font-mono">
|
||||
{import.meta.env.VITE_OPENCODE_CHANNEL.toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="opencode-titlebar-left" class="flex items-center gap-3 min-w-0 px-2" />
|
||||
</div>
|
||||
|
||||
<div class="min-w-0 flex items-center justify-center pointer-events-none">
|
||||
|
||||
@@ -128,6 +128,7 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
|
||||
if (started) return run
|
||||
started = true
|
||||
run = (async () => {
|
||||
// oxlint-disable-next-line no-unmodified-loop-condition -- `started` is set to false by stop() which also aborts; both flags are checked to allow graceful exit
|
||||
while (!abort.signal.aborted && started) {
|
||||
attempt = new AbortController()
|
||||
lastEventAt = Date.now()
|
||||
|
||||
@@ -9,10 +9,9 @@ import type {
|
||||
} from "@opencode-ai/sdk/v2/client"
|
||||
import { showToast } from "@opencode-ai/ui/toast"
|
||||
import { getFilename } from "@opencode-ai/shared/util/path"
|
||||
import { createContext, getOwner, onCleanup, onMount, type ParentProps, untrack, useContext } from "solid-js"
|
||||
import { batch, createContext, getOwner, onCleanup, onMount, type ParentProps, untrack, useContext } from "solid-js"
|
||||
import { createStore, produce, reconcile } from "solid-js/store"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { Persist, persisted } from "@/utils/persist"
|
||||
import type { InitError } from "../pages/error"
|
||||
import { useGlobalSDK } from "./global-sdk"
|
||||
import { bootstrapDirectory, bootstrapGlobal, clearProviderRev } from "./global-sync/bootstrap"
|
||||
@@ -24,8 +23,8 @@ import { estimateRootSessionTotal, loadRootSessionsWithFallback } from "./global
|
||||
import { trimSessions } from "./global-sync/session-trim"
|
||||
import type { ProjectMeta } from "./global-sync/types"
|
||||
import { SESSION_RECENT_LIMIT } from "./global-sync/types"
|
||||
import { sanitizeProject } from "./global-sync/utils"
|
||||
import { formatServerError } from "@/utils/server-errors"
|
||||
import { queryOptions, skipToken, useQueryClient } from "@tanstack/solid-query"
|
||||
|
||||
type GlobalStore = {
|
||||
ready: boolean
|
||||
@@ -41,6 +40,9 @@ type GlobalStore = {
|
||||
reload: undefined | "pending" | "complete"
|
||||
}
|
||||
|
||||
export const loadSessionsQuery = (directory: string) =>
|
||||
queryOptions<null>({ queryKey: [directory, "loadSessions"], queryFn: skipToken })
|
||||
|
||||
function createGlobalSync() {
|
||||
const globalSDK = useGlobalSDK()
|
||||
const language = useLanguage()
|
||||
@@ -52,53 +54,30 @@ function createGlobalSync() {
|
||||
const sessionLoads = new Map<string, Promise<void>>()
|
||||
const sessionMeta = new Map<string, { limit: number }>()
|
||||
|
||||
const [projectCache, setProjectCache, projectInit] = persisted(
|
||||
Persist.global("globalSync.project", ["globalSync.project.v1"]),
|
||||
createStore({ value: [] as Project[] }),
|
||||
)
|
||||
|
||||
const [globalStore, setGlobalStore] = createStore<GlobalStore>({
|
||||
ready: false,
|
||||
path: { state: "", config: "", worktree: "", directory: "", home: "" },
|
||||
project: projectCache.value,
|
||||
project: [],
|
||||
session_todo: {},
|
||||
provider: { all: [], connected: [], default: {} },
|
||||
provider_auth: {},
|
||||
config: {},
|
||||
reload: undefined,
|
||||
})
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
let active = true
|
||||
let projectWritten = false
|
||||
let bootedAt = 0
|
||||
let bootingRoot = false
|
||||
let eventFrame: number | undefined
|
||||
let eventTimer: ReturnType<typeof setTimeout> | undefined
|
||||
|
||||
onCleanup(() => {
|
||||
active = false
|
||||
})
|
||||
onCleanup(() => {
|
||||
if (eventFrame !== undefined) cancelAnimationFrame(eventFrame)
|
||||
if (eventTimer !== undefined) clearTimeout(eventTimer)
|
||||
})
|
||||
|
||||
const cacheProjects = () => {
|
||||
setProjectCache(
|
||||
"value",
|
||||
untrack(() => globalStore.project.map(sanitizeProject)),
|
||||
)
|
||||
}
|
||||
|
||||
const setProjects = (next: Project[] | ((draft: Project[]) => void)) => {
|
||||
projectWritten = true
|
||||
if (typeof next === "function") {
|
||||
setGlobalStore("project", produce(next))
|
||||
cacheProjects()
|
||||
return
|
||||
}
|
||||
const setProjects = (next: Project[] | ((draft: Project[]) => Project[])) => {
|
||||
setGlobalStore("project", next)
|
||||
cacheProjects()
|
||||
}
|
||||
|
||||
const setBootStore = ((...input: unknown[]) => {
|
||||
@@ -111,22 +90,12 @@ function createGlobalSync() {
|
||||
|
||||
const set = ((...input: unknown[]) => {
|
||||
if (input[0] === "project" && (Array.isArray(input[1]) || typeof input[1] === "function")) {
|
||||
setProjects(input[1] as Project[] | ((draft: Project[]) => void))
|
||||
setProjects(input[1] as Project[] | ((draft: Project[]) => Project[]))
|
||||
return input[1]
|
||||
}
|
||||
return (setGlobalStore as (...args: unknown[]) => unknown)(...input)
|
||||
}) as typeof setGlobalStore
|
||||
|
||||
if (projectInit instanceof Promise) {
|
||||
void projectInit.then(() => {
|
||||
if (!active) return
|
||||
if (projectWritten) return
|
||||
const cached = projectCache.value
|
||||
if (cached.length === 0) return
|
||||
setGlobalStore("project", cached)
|
||||
})
|
||||
}
|
||||
|
||||
const setSessionTodo = (sessionID: string, todos: Todo[] | undefined) => {
|
||||
if (!sessionID) return
|
||||
if (!todos) {
|
||||
@@ -198,46 +167,55 @@ function createGlobalSync() {
|
||||
}
|
||||
|
||||
const limit = Math.max(store.limit + SESSION_RECENT_LIMIT, SESSION_RECENT_LIMIT)
|
||||
const promise = loadRootSessionsWithFallback({
|
||||
directory,
|
||||
limit,
|
||||
list: (query) => globalSDK.client.session.list(query),
|
||||
})
|
||||
.then((x) => {
|
||||
const nonArchived = (x.data ?? [])
|
||||
.filter((s) => !!s?.id)
|
||||
.filter((s) => !s.time?.archived)
|
||||
.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))
|
||||
const limit = store.limit
|
||||
const childSessions = store.session.filter((s) => !!s.parentID)
|
||||
const sessions = trimSessions([...nonArchived, ...childSessions], {
|
||||
limit,
|
||||
permission: store.permission,
|
||||
})
|
||||
setStore(
|
||||
"sessionTotal",
|
||||
estimateRootSessionTotal({
|
||||
count: nonArchived.length,
|
||||
limit: x.limit,
|
||||
limited: x.limited,
|
||||
}),
|
||||
)
|
||||
setStore("session", reconcile(sessions, { key: "id" }))
|
||||
cleanupDroppedSessionCaches(store, setStore, sessions, setSessionTodo)
|
||||
sessionMeta.set(directory, { limit })
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Failed to load sessions", err)
|
||||
const project = getFilename(directory)
|
||||
showToast({
|
||||
variant: "error",
|
||||
title: language.t("toast.session.listFailed.title", { project }),
|
||||
description: formatServerError(err, language.t),
|
||||
})
|
||||
const promise = queryClient
|
||||
.fetchQuery({
|
||||
...loadSessionsQuery(directory),
|
||||
queryFn: () =>
|
||||
loadRootSessionsWithFallback({
|
||||
directory,
|
||||
limit,
|
||||
list: (query) => globalSDK.client.session.list(query),
|
||||
})
|
||||
.then((x) => {
|
||||
const nonArchived = (x.data ?? [])
|
||||
.filter((s) => !!s?.id)
|
||||
.filter((s) => !s.time?.archived)
|
||||
.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))
|
||||
const limit = store.limit
|
||||
const childSessions = store.session.filter((s) => !!s.parentID)
|
||||
const sessions = trimSessions([...nonArchived, ...childSessions], {
|
||||
limit,
|
||||
permission: store.permission,
|
||||
})
|
||||
batch(() => {
|
||||
setStore(
|
||||
"sessionTotal",
|
||||
estimateRootSessionTotal({
|
||||
count: nonArchived.length,
|
||||
limit: x.limit,
|
||||
limited: x.limited,
|
||||
}),
|
||||
)
|
||||
setStore("session", reconcile(sessions, { key: "id" }))
|
||||
cleanupDroppedSessionCaches(store, setStore, sessions, setSessionTodo)
|
||||
})
|
||||
sessionMeta.set(directory, { limit })
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Failed to load sessions", err)
|
||||
const project = getFilename(directory)
|
||||
showToast({
|
||||
variant: "error",
|
||||
title: language.t("toast.session.listFailed.title", { project }),
|
||||
description: formatServerError(err, language.t),
|
||||
})
|
||||
})
|
||||
.then(() => null),
|
||||
})
|
||||
.then(() => {})
|
||||
|
||||
sessionLoads.set(directory, promise)
|
||||
promise.finally(() => {
|
||||
void promise.finally(() => {
|
||||
sessionLoads.delete(directory)
|
||||
children.unpin(directory)
|
||||
})
|
||||
@@ -250,7 +228,7 @@ function createGlobalSync() {
|
||||
if (pending) return pending
|
||||
|
||||
children.pin(directory)
|
||||
const promise = (async () => {
|
||||
const promise = Promise.resolve().then(async () => {
|
||||
const child = children.ensureChild(directory)
|
||||
const cache = children.vcsCache.get(directory)
|
||||
if (!cache) return
|
||||
@@ -269,11 +247,12 @@ function createGlobalSync() {
|
||||
vcsCache: cache,
|
||||
loadSessions,
|
||||
translate: language.t,
|
||||
queryClient,
|
||||
})
|
||||
})()
|
||||
})
|
||||
|
||||
booting.set(directory, promise)
|
||||
promise.finally(() => {
|
||||
void promise.finally(() => {
|
||||
booting.delete(directory)
|
||||
children.unpin(directory)
|
||||
})
|
||||
@@ -285,6 +264,19 @@ function createGlobalSync() {
|
||||
const event = e.details
|
||||
const recent = bootingRoot || Date.now() - bootedAt < 1500
|
||||
|
||||
if (event.type === "session.error") {
|
||||
const error = event.properties.error
|
||||
if (error?.name !== "MessageAbortedError") {
|
||||
console.error("[global-sync] session error", {
|
||||
scope: directory === "global" ? "global" : "workspace",
|
||||
directory: directory === "global" ? undefined : directory,
|
||||
project: directory === "global" ? undefined : getFilename(directory),
|
||||
sessionID: event.properties.sessionID,
|
||||
error,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (directory === "global") {
|
||||
applyGlobalEvent({
|
||||
event,
|
||||
@@ -317,7 +309,7 @@ function createGlobalSync() {
|
||||
setSessionTodo,
|
||||
vcsCache: children.vcsCache.get(directory),
|
||||
loadLsp: () => {
|
||||
sdkFor(directory)
|
||||
void sdkFor(directory)
|
||||
.lsp.status()
|
||||
.then((x) => {
|
||||
setStore("lsp", x.data ?? [])
|
||||
@@ -346,6 +338,7 @@ function createGlobalSync() {
|
||||
translate: language.t,
|
||||
formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }),
|
||||
setGlobalStore: setBootStore,
|
||||
queryClient,
|
||||
})
|
||||
bootedAt = Date.now()
|
||||
} finally {
|
||||
@@ -359,13 +352,13 @@ function createGlobalSync() {
|
||||
eventFrame = undefined
|
||||
eventTimer = setTimeout(() => {
|
||||
eventTimer = undefined
|
||||
globalSDK.event.start()
|
||||
void globalSDK.event.start()
|
||||
}, 0)
|
||||
})
|
||||
} else {
|
||||
eventTimer = setTimeout(() => {
|
||||
eventTimer = undefined
|
||||
globalSDK.event.start()
|
||||
void globalSDK.event.start()
|
||||
}, 0)
|
||||
}
|
||||
void bootstrap()
|
||||
|
||||
@@ -18,6 +18,7 @@ import { reconcile, type SetStoreFunction, type Store } from "solid-js/store"
|
||||
import type { State, VcsCache } from "./types"
|
||||
import { cmp, normalizeAgentList, normalizeProviderList } from "./utils"
|
||||
import { formatServerError } from "@/utils/server-errors"
|
||||
import { QueryClient, queryOptions, skipToken } from "@tanstack/solid-query"
|
||||
|
||||
type GlobalStore = {
|
||||
ready: boolean
|
||||
@@ -65,28 +66,13 @@ function runAll(list: Array<() => Promise<unknown>>) {
|
||||
return Promise.allSettled(list.map((item) => item()))
|
||||
}
|
||||
|
||||
function showErrors(input: {
|
||||
errors: unknown[]
|
||||
title: string
|
||||
translate: (key: string, vars?: Record<string, string | number>) => string
|
||||
formatMoreCount: (count: number) => string
|
||||
}) {
|
||||
if (input.errors.length === 0) return
|
||||
const message = formatServerError(input.errors[0], input.translate)
|
||||
const more = input.errors.length > 1 ? input.formatMoreCount(input.errors.length - 1) : ""
|
||||
showToast({
|
||||
variant: "error",
|
||||
title: input.title,
|
||||
description: message + more,
|
||||
})
|
||||
}
|
||||
|
||||
export async function bootstrapGlobal(input: {
|
||||
globalSDK: OpencodeClient
|
||||
requestFailedTitle: string
|
||||
translate: (key: string, vars?: Record<string, string | number>) => string
|
||||
formatMoreCount: (count: number) => string
|
||||
setGlobalStore: SetStoreFunction<GlobalStore>
|
||||
queryClient: QueryClient
|
||||
}) {
|
||||
const fast = [
|
||||
() =>
|
||||
@@ -95,15 +81,20 @@ export async function bootstrapGlobal(input: {
|
||||
input.setGlobalStore("config", x.data!)
|
||||
}),
|
||||
),
|
||||
() =>
|
||||
retry(() =>
|
||||
input.globalSDK.provider.list().then((x) => {
|
||||
input.setGlobalStore("provider", normalizeProviderList(x.data!))
|
||||
}),
|
||||
),
|
||||
]
|
||||
|
||||
const slow = [
|
||||
() =>
|
||||
input.queryClient.fetchQuery({
|
||||
...loadProvidersQuery(null),
|
||||
queryFn: () =>
|
||||
retry(() =>
|
||||
input.globalSDK.provider.list().then((x) => {
|
||||
input.setGlobalStore("provider", normalizeProviderList(x.data!))
|
||||
return null
|
||||
}),
|
||||
),
|
||||
}),
|
||||
() =>
|
||||
retry(() =>
|
||||
input.globalSDK.path.get().then((x) => {
|
||||
@@ -188,6 +179,47 @@ function warmSessions(input: {
|
||||
).then(() => undefined)
|
||||
}
|
||||
|
||||
export const loadProvidersQuery = (directory: string | null) =>
|
||||
queryOptions<null>({ queryKey: [directory, "providers"], queryFn: skipToken })
|
||||
|
||||
export const loadAgentsQuery = (
|
||||
directory: string | null,
|
||||
sdk?: OpencodeClient,
|
||||
transform?: (x: Awaited<ReturnType<OpencodeClient["app"]["agents"]>>) => void,
|
||||
) =>
|
||||
queryOptions<null>({
|
||||
queryKey: [directory, "agents"],
|
||||
queryFn:
|
||||
sdk && transform
|
||||
? () =>
|
||||
retry(() =>
|
||||
sdk.app
|
||||
.agents()
|
||||
.then(transform)
|
||||
.then(() => null),
|
||||
)
|
||||
: skipToken,
|
||||
})
|
||||
|
||||
export const loadPathQuery = (
|
||||
directory: string | null,
|
||||
sdk?: OpencodeClient,
|
||||
transform?: (x: Awaited<ReturnType<OpencodeClient["path"]["get"]>>) => void,
|
||||
) =>
|
||||
queryOptions<Path>({
|
||||
queryKey: [directory, "path"],
|
||||
queryFn:
|
||||
sdk && transform
|
||||
? () =>
|
||||
retry(() =>
|
||||
sdk.path.get().then(async (x) => {
|
||||
transform(x)
|
||||
return x.data!
|
||||
}),
|
||||
)
|
||||
: skipToken,
|
||||
})
|
||||
|
||||
export async function bootstrapDirectory(input: {
|
||||
directory: string
|
||||
sdk: OpencodeClient
|
||||
@@ -202,6 +234,7 @@ export async function bootstrapDirectory(input: {
|
||||
project: Project[]
|
||||
provider: ProviderListResponse
|
||||
}
|
||||
queryClient: QueryClient
|
||||
}) {
|
||||
const loading = input.store.status !== "complete"
|
||||
const seededProject = projectID(input.directory, input.global.project)
|
||||
@@ -223,139 +256,131 @@ export async function bootstrapDirectory(input: {
|
||||
input.setStore("lsp", [])
|
||||
if (loading) input.setStore("status", "partial")
|
||||
|
||||
const fast = [
|
||||
() => retry(() => input.sdk.app.agents().then((x) => input.setStore("agent", normalizeAgentList(x.data)))),
|
||||
() => retry(() => input.sdk.config.get().then((x) => input.setStore("config", x.data!))),
|
||||
() => retry(() => input.sdk.session.status().then((x) => input.setStore("session_status", x.data!))),
|
||||
]
|
||||
|
||||
const slow = [
|
||||
() =>
|
||||
seededProject
|
||||
? Promise.resolve()
|
||||
: retry(() => input.sdk.project.current()).then((x) => input.setStore("project", x.data!.id)),
|
||||
() =>
|
||||
seededPath
|
||||
? Promise.resolve()
|
||||
: retry(() =>
|
||||
input.sdk.path.get().then((x) => {
|
||||
input.setStore("path", x.data!)
|
||||
const rev = (providerRev.get(input.directory) ?? 0) + 1
|
||||
providerRev.set(input.directory, rev)
|
||||
;(async () => {
|
||||
const slow = [
|
||||
() => Promise.resolve(input.loadSessions(input.directory)),
|
||||
() =>
|
||||
input.queryClient.ensureQueryData(
|
||||
loadAgentsQuery(input.directory, input.sdk, (x) => input.setStore("agent", normalizeAgentList(x.data))),
|
||||
),
|
||||
() => retry(() => input.sdk.config.get().then((x) => input.setStore("config", x.data!))),
|
||||
() => retry(() => input.sdk.session.status().then((x) => input.setStore("session_status", x.data!))),
|
||||
!seededProject &&
|
||||
(() => retry(() => input.sdk.project.current()).then((x) => input.setStore("project", x.data!.id))),
|
||||
!seededPath &&
|
||||
(() =>
|
||||
input.queryClient.ensureQueryData(
|
||||
loadPathQuery(input.directory, input.sdk, (x) => {
|
||||
const next = projectID(x.data?.directory ?? input.directory, input.global.project)
|
||||
if (next) input.setStore("project", next)
|
||||
}),
|
||||
),
|
||||
() =>
|
||||
retry(() =>
|
||||
input.sdk.vcs.get().then((x) => {
|
||||
const next = x.data ?? input.store.vcs
|
||||
input.setStore("vcs", next)
|
||||
if (next) input.vcsCache.setStore("value", next)
|
||||
)),
|
||||
() =>
|
||||
retry(() =>
|
||||
input.sdk.vcs.get().then((x) => {
|
||||
const next = x.data ?? input.store.vcs
|
||||
input.setStore("vcs", next)
|
||||
if (next) input.vcsCache.setStore("value", next)
|
||||
}),
|
||||
),
|
||||
() => retry(() => input.sdk.command.list().then((x) => input.setStore("command", x.data ?? []))),
|
||||
() =>
|
||||
retry(() =>
|
||||
input.sdk.permission.list().then((x) => {
|
||||
const ids = (x.data ?? []).map((perm) => perm?.sessionID).filter((id): id is string => !!id)
|
||||
const grouped = groupBySession(
|
||||
(x.data ?? []).filter((perm): perm is PermissionRequest => !!perm?.id && !!perm.sessionID),
|
||||
)
|
||||
return warmSessions({ ids, store: input.store, setStore: input.setStore, sdk: input.sdk }).then(() =>
|
||||
batch(() => {
|
||||
for (const sessionID of Object.keys(input.store.permission)) {
|
||||
if (grouped[sessionID]) continue
|
||||
input.setStore("permission", sessionID, [])
|
||||
}
|
||||
for (const [sessionID, permissions] of Object.entries(grouped)) {
|
||||
input.setStore(
|
||||
"permission",
|
||||
sessionID,
|
||||
reconcile(
|
||||
permissions.filter((p) => !!p?.id).sort((a, b) => cmp(a.id, b.id)),
|
||||
{ key: "id" },
|
||||
),
|
||||
)
|
||||
}
|
||||
}),
|
||||
)
|
||||
}),
|
||||
),
|
||||
() =>
|
||||
retry(() =>
|
||||
input.sdk.question.list().then((x) => {
|
||||
const ids = (x.data ?? []).map((question) => question?.sessionID).filter((id): id is string => !!id)
|
||||
const grouped = groupBySession((x.data ?? []).filter((q): q is QuestionRequest => !!q?.id && !!q.sessionID))
|
||||
return warmSessions({ ids, store: input.store, setStore: input.setStore, sdk: input.sdk }).then(() =>
|
||||
batch(() => {
|
||||
for (const sessionID of Object.keys(input.store.question)) {
|
||||
if (grouped[sessionID]) continue
|
||||
input.setStore("question", sessionID, [])
|
||||
}
|
||||
for (const [sessionID, questions] of Object.entries(grouped)) {
|
||||
input.setStore(
|
||||
"question",
|
||||
sessionID,
|
||||
reconcile(
|
||||
questions.filter((q) => !!q?.id).sort((a, b) => cmp(a.id, b.id)),
|
||||
{ key: "id" },
|
||||
),
|
||||
)
|
||||
}
|
||||
}),
|
||||
)
|
||||
}),
|
||||
),
|
||||
() => Promise.resolve(input.loadSessions(input.directory)),
|
||||
() =>
|
||||
retry(() =>
|
||||
input.sdk.mcp.status().then((x) => {
|
||||
input.setStore("mcp", x.data!)
|
||||
input.setStore("mcp_ready", true)
|
||||
}),
|
||||
),
|
||||
() =>
|
||||
input.queryClient.ensureQueryData({
|
||||
...loadProvidersQuery(input.directory),
|
||||
queryFn: () =>
|
||||
retry(() => input.sdk.provider.list())
|
||||
.then((x) => {
|
||||
if (providerRev.get(input.directory) !== rev) return
|
||||
input.setStore("provider", normalizeProviderList(x.data!))
|
||||
input.setStore("provider_ready", true)
|
||||
})
|
||||
.catch((err) => {
|
||||
if (providerRev.get(input.directory) !== rev) console.error("Failed to refresh provider list", err)
|
||||
const project = getFilename(input.directory)
|
||||
showToast({
|
||||
variant: "error",
|
||||
title: input.translate("toast.project.reloadFailed.title", { project }),
|
||||
description: formatServerError(err, input.translate),
|
||||
})
|
||||
})
|
||||
.then(() => null),
|
||||
}),
|
||||
),
|
||||
() => retry(() => input.sdk.command.list().then((x) => input.setStore("command", x.data ?? []))),
|
||||
() =>
|
||||
retry(() =>
|
||||
input.sdk.permission.list().then((x) => {
|
||||
const ids = (x.data ?? []).map((perm) => perm?.sessionID).filter((id): id is string => !!id)
|
||||
const grouped = groupBySession(
|
||||
(x.data ?? []).filter((perm): perm is PermissionRequest => !!perm?.id && !!perm.sessionID),
|
||||
)
|
||||
return warmSessions({ ids, store: input.store, setStore: input.setStore, sdk: input.sdk }).then(() =>
|
||||
batch(() => {
|
||||
for (const sessionID of Object.keys(input.store.permission)) {
|
||||
if (grouped[sessionID]) continue
|
||||
input.setStore("permission", sessionID, [])
|
||||
}
|
||||
for (const [sessionID, permissions] of Object.entries(grouped)) {
|
||||
input.setStore(
|
||||
"permission",
|
||||
sessionID,
|
||||
reconcile(
|
||||
permissions.filter((p) => !!p?.id).sort((a, b) => cmp(a.id, b.id)),
|
||||
{ key: "id" },
|
||||
),
|
||||
)
|
||||
}
|
||||
}),
|
||||
)
|
||||
}),
|
||||
),
|
||||
() =>
|
||||
retry(() =>
|
||||
input.sdk.question.list().then((x) => {
|
||||
const ids = (x.data ?? []).map((question) => question?.sessionID).filter((id): id is string => !!id)
|
||||
const grouped = groupBySession((x.data ?? []).filter((q): q is QuestionRequest => !!q?.id && !!q.sessionID))
|
||||
return warmSessions({ ids, store: input.store, setStore: input.setStore, sdk: input.sdk }).then(() =>
|
||||
batch(() => {
|
||||
for (const sessionID of Object.keys(input.store.question)) {
|
||||
if (grouped[sessionID]) continue
|
||||
input.setStore("question", sessionID, [])
|
||||
}
|
||||
for (const [sessionID, questions] of Object.entries(grouped)) {
|
||||
input.setStore(
|
||||
"question",
|
||||
sessionID,
|
||||
reconcile(
|
||||
questions.filter((q) => !!q?.id).sort((a, b) => cmp(a.id, b.id)),
|
||||
{ key: "id" },
|
||||
),
|
||||
)
|
||||
}
|
||||
}),
|
||||
)
|
||||
}),
|
||||
),
|
||||
() => Promise.resolve(input.loadSessions(input.directory)),
|
||||
() =>
|
||||
retry(() =>
|
||||
input.sdk.mcp.status().then((x) => {
|
||||
input.setStore("mcp", x.data!)
|
||||
input.setStore("mcp_ready", true)
|
||||
}),
|
||||
),
|
||||
]
|
||||
].filter(Boolean) as (() => Promise<any>)[]
|
||||
|
||||
const errs = errors(await runAll(fast))
|
||||
if (errs.length > 0) {
|
||||
console.error("Failed to bootstrap instance", errs[0])
|
||||
const project = getFilename(input.directory)
|
||||
showToast({
|
||||
variant: "error",
|
||||
title: input.translate("toast.project.reloadFailed.title", { project }),
|
||||
description: formatServerError(errs[0], input.translate),
|
||||
})
|
||||
}
|
||||
|
||||
await waitForPaint()
|
||||
const slowErrs = errors(await runAll(slow))
|
||||
if (slowErrs.length > 0) {
|
||||
console.error("Failed to finish bootstrap instance", slowErrs[0])
|
||||
const project = getFilename(input.directory)
|
||||
showToast({
|
||||
variant: "error",
|
||||
title: input.translate("toast.project.reloadFailed.title", { project }),
|
||||
description: formatServerError(slowErrs[0], input.translate),
|
||||
})
|
||||
}
|
||||
|
||||
if (loading && errs.length === 0 && slowErrs.length === 0) input.setStore("status", "complete")
|
||||
|
||||
const rev = (providerRev.get(input.directory) ?? 0) + 1
|
||||
providerRev.set(input.directory, rev)
|
||||
void retry(() => input.sdk.provider.list())
|
||||
.then((x) => {
|
||||
if (providerRev.get(input.directory) !== rev) return
|
||||
input.setStore("provider", normalizeProviderList(x.data!))
|
||||
input.setStore("provider_ready", true)
|
||||
})
|
||||
.catch((err) => {
|
||||
if (providerRev.get(input.directory) !== rev) return
|
||||
console.error("Failed to refresh provider list", err)
|
||||
await waitForPaint()
|
||||
const slowErrs = errors(await runAll(slow))
|
||||
if (slowErrs.length > 0) {
|
||||
console.error("Failed to finish bootstrap instance", slowErrs[0])
|
||||
const project = getFilename(input.directory)
|
||||
showToast({
|
||||
variant: "error",
|
||||
title: input.translate("toast.project.reloadFailed.title", { project }),
|
||||
description: formatServerError(err, input.translate),
|
||||
description: formatServerError(slowErrs[0], input.translate),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (loading && slowErrs.length === 0) input.setStore("status", "complete")
|
||||
})()
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ import {
|
||||
type VcsCache,
|
||||
} from "./types"
|
||||
import { canDisposeDirectory, pickDirectoriesToEvict } from "./eviction"
|
||||
import { useQuery } from "@tanstack/solid-query"
|
||||
import { loadPathQuery } from "./bootstrap"
|
||||
|
||||
export function createChildStoreManager(input: {
|
||||
owner: Owner
|
||||
@@ -154,16 +156,21 @@ export function createChildStoreManager(input: {
|
||||
|
||||
const init = () =>
|
||||
createRoot((dispose) => {
|
||||
const initialMeta = meta[0].value
|
||||
const initialIcon = icon[0].value
|
||||
|
||||
const pathQuery = useQuery(() => loadPathQuery(directory))
|
||||
const child = createStore<State>({
|
||||
project: "",
|
||||
projectMeta: initialMeta,
|
||||
projectMeta: undefined,
|
||||
icon: initialIcon,
|
||||
provider_ready: false,
|
||||
provider: { all: [], connected: [], default: {} },
|
||||
config: {},
|
||||
path: { state: "", config: "", worktree: "", directory: "", home: "" },
|
||||
get path() {
|
||||
if (pathQuery.isLoading || !pathQuery.data)
|
||||
return { state: "", config: "", worktree: "", directory: "", home: "" }
|
||||
return pathQuery.data
|
||||
},
|
||||
status: "loading" as const,
|
||||
agent: [],
|
||||
command: [],
|
||||
@@ -200,11 +207,6 @@ export function createChildStoreManager(input: {
|
||||
child[1]("vcs", (value) => value ?? cached)
|
||||
})
|
||||
|
||||
onPersistedInit(meta[2], () => {
|
||||
if (child[0].projectMeta !== initialMeta) return
|
||||
child[1]("projectMeta", meta[0].value)
|
||||
})
|
||||
|
||||
onPersistedInit(icon[2], () => {
|
||||
if (child[0].icon !== initialIcon) return
|
||||
child[1]("icon", icon[0].value)
|
||||
@@ -243,8 +245,8 @@ export function createChildStoreManager(input: {
|
||||
const cached = metaCache.get(directory)
|
||||
if (!cached) return
|
||||
const previous = store.projectMeta ?? {}
|
||||
const icon = patch.icon ? { ...(previous.icon ?? {}), ...patch.icon } : previous.icon
|
||||
const commands = patch.commands ? { ...(previous.commands ?? {}), ...patch.commands } : previous.commands
|
||||
const icon = patch.icon ? { ...previous.icon, ...patch.icon } : previous.icon
|
||||
const commands = patch.commands ? { ...previous.commands, ...patch.commands } : previous.commands
|
||||
const next = {
|
||||
...previous,
|
||||
...patch,
|
||||
|
||||
@@ -21,7 +21,7 @@ const SKIP_PARTS = new Set(["patch", "step-start", "step-finish"])
|
||||
export function applyGlobalEvent(input: {
|
||||
event: { type: string; properties?: unknown }
|
||||
project: Project[]
|
||||
setGlobalProject: (next: Project[] | ((draft: Project[]) => void)) => void
|
||||
setGlobalProject: (next: Project[] | ((draft: Project[]) => Project[])) => void
|
||||
refresh: () => void
|
||||
}) {
|
||||
if (input.event.type === "global.disposed" || input.event.type === "server.connected") {
|
||||
@@ -33,14 +33,18 @@ export function applyGlobalEvent(input: {
|
||||
const properties = input.event.properties as Project
|
||||
const result = Binary.search(input.project, properties.id, (s) => s.id)
|
||||
if (result.found) {
|
||||
input.setGlobalProject((draft) => {
|
||||
draft[result.index] = { ...draft[result.index], ...properties }
|
||||
})
|
||||
input.setGlobalProject(
|
||||
produce((draft) => {
|
||||
draft[result.index] = { ...draft[result.index], ...properties }
|
||||
}),
|
||||
)
|
||||
return
|
||||
}
|
||||
input.setGlobalProject((draft) => {
|
||||
draft.splice(result.index, 0, properties)
|
||||
})
|
||||
input.setGlobalProject(
|
||||
produce((draft) => {
|
||||
draft.splice(result.index, 0, properties)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
function cleanupSessionCaches(
|
||||
|
||||
@@ -63,6 +63,7 @@ export function createRefreshQueue(input: QueueInput) {
|
||||
}
|
||||
} finally {
|
||||
running = false
|
||||
// oxlint-disable-next-line no-unsafe-finally -- intentional: early return skips schedule() when paused
|
||||
if (input.paused()) return
|
||||
if (root || queued.size) schedule()
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import type {
|
||||
Part,
|
||||
Path,
|
||||
PermissionRequest,
|
||||
Project,
|
||||
ProviderListResponse,
|
||||
QuestionRequest,
|
||||
Session,
|
||||
|
||||
@@ -344,7 +344,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
||||
return
|
||||
}
|
||||
|
||||
setStore("sessionView", sessionKey, "scroll", (prev) => ({ ...(prev ?? {}), ...next }))
|
||||
setStore("sessionView", sessionKey, "scroll", (prev) => ({ ...prev, ...next }))
|
||||
prune(keep)
|
||||
},
|
||||
})
|
||||
@@ -391,37 +391,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
||||
? globalSync.data.project.find((x) => x.id === projectID)
|
||||
: globalSync.data.project.find((x) => x.worktree === project.worktree)
|
||||
|
||||
const local = childStore.projectMeta
|
||||
const localOverride =
|
||||
local?.name !== undefined ||
|
||||
local?.commands?.start !== undefined ||
|
||||
local?.icon?.override !== undefined ||
|
||||
local?.icon?.color !== undefined
|
||||
|
||||
const base = {
|
||||
...(metadata ?? {}),
|
||||
...project,
|
||||
icon: {
|
||||
url: metadata?.icon?.url,
|
||||
override: metadata?.icon?.override ?? childStore.icon,
|
||||
color: metadata?.icon?.color,
|
||||
},
|
||||
}
|
||||
|
||||
const isGlobal = projectID === "global" || (metadata?.id === undefined && localOverride)
|
||||
if (!isGlobal) return base
|
||||
|
||||
return {
|
||||
...base,
|
||||
id: base.id ?? "global",
|
||||
name: local?.name,
|
||||
commands: local?.commands,
|
||||
icon: {
|
||||
url: base.icon?.url,
|
||||
override: local?.icon?.override,
|
||||
color: local?.icon?.color,
|
||||
},
|
||||
}
|
||||
return { ...metadata, ...project }
|
||||
}
|
||||
|
||||
const roots = createMemo(() => {
|
||||
@@ -516,7 +486,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
||||
}
|
||||
|
||||
for (const project of projects) {
|
||||
if (project.icon?.color) continue
|
||||
if (project.icon?.color || project.icon?.override || project.icon?.url) continue
|
||||
const worktree = project.worktree
|
||||
const existing = colors[worktree]
|
||||
const color = existing ?? pickAvailableColor(used)
|
||||
@@ -582,7 +552,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
||||
open(directory: string) {
|
||||
const root = rootFor(directory)
|
||||
if (server.projects.list().find((x) => x.worktree === root)) return
|
||||
globalSync.project.loadSessions(root)
|
||||
void globalSync.project.loadSessions(root)
|
||||
server.projects.open(root)
|
||||
},
|
||||
close(directory: string) {
|
||||
|
||||
@@ -49,11 +49,11 @@ export type Platform = {
|
||||
/** Storage mechanism, defaults to localStorage */
|
||||
storage?: (name?: string) => SyncStorage | AsyncStorage
|
||||
|
||||
/** Check for updates (Tauri only) */
|
||||
/** Check for a downloadable desktop update */
|
||||
checkUpdate?(): Promise<UpdateInfo>
|
||||
|
||||
/** Install updates (Tauri only) */
|
||||
update?(): Promise<void>
|
||||
/** Install the downloaded update using the platform restart flow */
|
||||
updateAndRestart?(): Promise<void>
|
||||
|
||||
/** Fetch override */
|
||||
fetch?: typeof fetch
|
||||
|
||||
@@ -185,9 +185,9 @@ function createPromptSession(dir: string, id: string | undefined) {
|
||||
|
||||
return {
|
||||
ready,
|
||||
current: createMemo(() => store.prompt),
|
||||
current: () => store.prompt,
|
||||
cursor: createMemo(() => store.cursor),
|
||||
dirty: createMemo(() => !isPromptEqual(store.prompt, DEFAULT_PROMPT)),
|
||||
dirty: () => !isPromptEqual(store.prompt, DEFAULT_PROMPT),
|
||||
context: {
|
||||
items: createMemo(() => store.context.items),
|
||||
add(item: ContextItem) {
|
||||
@@ -277,7 +277,7 @@ export const { use: usePrompt, provider: PromptProvider } = createSimpleContext(
|
||||
const pick = (scope?: Scope) => (scope ? load(scope.dir, scope.id) : session())
|
||||
|
||||
return {
|
||||
ready: () => session().ready(),
|
||||
ready: () => session().ready,
|
||||
current: () => session().current(),
|
||||
cursor: () => session().cursor(),
|
||||
dirty: () => session().dirty(),
|
||||
|
||||
@@ -23,9 +23,15 @@ export interface Settings {
|
||||
autoSave: boolean
|
||||
releaseNotes: boolean
|
||||
followup: "queue" | "steer"
|
||||
showFileTree: boolean
|
||||
showNavigation: boolean
|
||||
showSearch: boolean
|
||||
showStatus: boolean
|
||||
showTerminal: boolean
|
||||
showReasoningSummaries: boolean
|
||||
shellToolPartsExpanded: boolean
|
||||
editToolPartsExpanded: boolean
|
||||
showSessionProgressBar: boolean
|
||||
}
|
||||
updates: {
|
||||
startup: boolean
|
||||
@@ -34,6 +40,7 @@ export interface Settings {
|
||||
fontSize: number
|
||||
mono: string
|
||||
sans: string
|
||||
terminal: string
|
||||
}
|
||||
keybinds: Record<string, string>
|
||||
permissions: {
|
||||
@@ -45,13 +52,17 @@ export interface Settings {
|
||||
|
||||
export const monoDefault = "System Mono"
|
||||
export const sansDefault = "System Sans"
|
||||
export const terminalDefault = "JetBrainsMono Nerd Font Mono"
|
||||
|
||||
const monoFallback =
|
||||
'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
|
||||
const sansFallback = 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'
|
||||
const terminalFallback =
|
||||
'"JetBrainsMono Nerd Font Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
|
||||
|
||||
const monoBase = monoFallback
|
||||
const sansBase = sansFallback
|
||||
const terminalBase = terminalFallback
|
||||
|
||||
function input(font: string | undefined) {
|
||||
return font ?? ""
|
||||
@@ -84,14 +95,28 @@ export function sansFontFamily(font: string | undefined) {
|
||||
return stack(font, sansBase)
|
||||
}
|
||||
|
||||
export function terminalInput(font: string | undefined) {
|
||||
return input(font)
|
||||
}
|
||||
|
||||
export function terminalFontFamily(font: string | undefined) {
|
||||
return stack(font, terminalBase)
|
||||
}
|
||||
|
||||
const defaultSettings: Settings = {
|
||||
general: {
|
||||
autoSave: true,
|
||||
releaseNotes: true,
|
||||
followup: "steer",
|
||||
showFileTree: false,
|
||||
showNavigation: false,
|
||||
showSearch: false,
|
||||
showStatus: false,
|
||||
showTerminal: false,
|
||||
showReasoningSummaries: false,
|
||||
shellToolPartsExpanded: false,
|
||||
editToolPartsExpanded: false,
|
||||
showSessionProgressBar: true,
|
||||
},
|
||||
updates: {
|
||||
startup: true,
|
||||
@@ -100,6 +125,7 @@ const defaultSettings: Settings = {
|
||||
fontSize: 14,
|
||||
mono: "",
|
||||
sans: "",
|
||||
terminal: "",
|
||||
},
|
||||
keybinds: {},
|
||||
permissions: {
|
||||
@@ -162,6 +188,26 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
|
||||
setFollowup(value: "queue" | "steer") {
|
||||
setStore("general", "followup", value === "queue" ? "steer" : value)
|
||||
},
|
||||
showFileTree: withFallback(() => store.general?.showFileTree, defaultSettings.general.showFileTree),
|
||||
setShowFileTree(value: boolean) {
|
||||
setStore("general", "showFileTree", value)
|
||||
},
|
||||
showNavigation: withFallback(() => store.general?.showNavigation, defaultSettings.general.showNavigation),
|
||||
setShowNavigation(value: boolean) {
|
||||
setStore("general", "showNavigation", value)
|
||||
},
|
||||
showSearch: withFallback(() => store.general?.showSearch, defaultSettings.general.showSearch),
|
||||
setShowSearch(value: boolean) {
|
||||
setStore("general", "showSearch", value)
|
||||
},
|
||||
showStatus: withFallback(() => store.general?.showStatus, defaultSettings.general.showStatus),
|
||||
setShowStatus(value: boolean) {
|
||||
setStore("general", "showStatus", value)
|
||||
},
|
||||
showTerminal: withFallback(() => store.general?.showTerminal, defaultSettings.general.showTerminal),
|
||||
setShowTerminal(value: boolean) {
|
||||
setStore("general", "showTerminal", value)
|
||||
},
|
||||
showReasoningSummaries: withFallback(
|
||||
() => store.general?.showReasoningSummaries,
|
||||
defaultSettings.general.showReasoningSummaries,
|
||||
@@ -183,6 +229,13 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
|
||||
setEditToolPartsExpanded(value: boolean) {
|
||||
setStore("general", "editToolPartsExpanded", value)
|
||||
},
|
||||
showSessionProgressBar: withFallback(
|
||||
() => store.general?.showSessionProgressBar,
|
||||
defaultSettings.general.showSessionProgressBar,
|
||||
),
|
||||
setShowSessionProgressBar(value: boolean) {
|
||||
setStore("general", "showSessionProgressBar", value)
|
||||
},
|
||||
},
|
||||
updates: {
|
||||
startup: withFallback(() => store.updates?.startup, defaultSettings.updates.startup),
|
||||
@@ -203,6 +256,10 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
|
||||
setUIFont(value: string) {
|
||||
setStore("appearance", "sans", value.trim() ? value : "")
|
||||
},
|
||||
terminalFont: withFallback(() => store.appearance?.terminal, defaultSettings.appearance.terminal),
|
||||
setTerminalFont(value: string) {
|
||||
setStore("appearance", "terminal", value.trim() ? value : "")
|
||||
},
|
||||
},
|
||||
keybinds: {
|
||||
get: (action: string) => store.keybinds?.[action],
|
||||
|
||||
@@ -117,7 +117,7 @@ export function clearWorkspaceTerminals(dir: string, sessionIDs?: string[], plat
|
||||
entry?.value.clear()
|
||||
}
|
||||
|
||||
removePersisted(Persist.workspace(dir, "terminal"), platform)
|
||||
void removePersisted(Persist.workspace(dir, "terminal"), platform)
|
||||
|
||||
const legacy = new Set(getLegacyTerminalStorageKeys(dir))
|
||||
for (const id of sessionIDs ?? []) {
|
||||
@@ -126,7 +126,7 @@ export function clearWorkspaceTerminals(dir: string, sessionIDs?: string[], plat
|
||||
}
|
||||
}
|
||||
for (const key of legacy) {
|
||||
removePersisted({ key }, platform)
|
||||
void removePersisted({ key }, platform)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
5
packages/app/src/env.d.ts
vendored
5
packages/app/src/env.d.ts
vendored
@@ -1,15 +1,14 @@
|
||||
import "solid-js"
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_OPENCODE_SERVER_HOST: string
|
||||
readonly VITE_OPENCODE_SERVER_PORT: string
|
||||
readonly VITE_OPENCODE_CHANNEL?: "dev" | "beta" | "prod"
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
}
|
||||
|
||||
declare module "solid-js" {
|
||||
export declare module "solid-js" {
|
||||
namespace JSX {
|
||||
interface Directives {
|
||||
sortable: true
|
||||
|
||||
@@ -210,7 +210,7 @@ export const dict = {
|
||||
"common.saving": "جارٍ الحفظ...",
|
||||
"common.default": "افتراضي",
|
||||
"common.attachment": "مرفق",
|
||||
"prompt.placeholder.shell": "أدخل أمر shell...",
|
||||
"prompt.placeholder.shell": "أدخل أمر shell... {{example}}",
|
||||
"prompt.placeholder.normal": 'اسأل أي شيء... "{{example}}"',
|
||||
"prompt.placeholder.simple": "اسأل أي شيء...",
|
||||
"prompt.placeholder.summarizeComments": "لخّص التعليقات…",
|
||||
@@ -565,7 +565,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "السمة",
|
||||
"settings.general.row.theme.description": "تخصيص سمة OpenCode.",
|
||||
"settings.general.row.font.title": "خط الكود",
|
||||
"settings.general.row.font.description": "خصّص الخط المستخدم في كتل التعليمات البرمجية والطرفيات",
|
||||
"settings.general.row.font.description": "خصّص الخط المستخدم في كتل التعليمات البرمجية",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "خط الواجهة",
|
||||
"settings.general.row.uiFont.description": "خصّص الخط المستخدم في الواجهة بأكملها",
|
||||
"settings.general.row.followup.title": "سلوك المتابعة",
|
||||
@@ -580,6 +582,8 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.title": "توسيع أجزاء أداة edit",
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"إظهار أجزاء أدوات edit و write و patch موسعة بشكل افتراضي في الشريط الزمني",
|
||||
"settings.general.row.showSessionProgressBar.title": "إظهار شريط تقدم الجلسة",
|
||||
"settings.general.row.showSessionProgressBar.description": "عرض شريط التقدم المتحرك أعلى الجلسة أثناء عمل الوكيل",
|
||||
"settings.general.row.wayland.title": "استخدام Wayland الأصلي",
|
||||
"settings.general.row.wayland.description": "تعطيل التراجع إلى X11 على Wayland. يتطلب إعادة التشغيل.",
|
||||
"settings.general.row.wayland.tooltip":
|
||||
|
||||
@@ -210,7 +210,7 @@ export const dict = {
|
||||
"common.saving": "Salvando...",
|
||||
"common.default": "Padrão",
|
||||
"common.attachment": "anexo",
|
||||
"prompt.placeholder.shell": "Digite comando do shell...",
|
||||
"prompt.placeholder.shell": "Digite comando do shell... {{example}}",
|
||||
"prompt.placeholder.normal": 'Pergunte qualquer coisa... "{{example}}"',
|
||||
"prompt.placeholder.simple": "Pergunte qualquer coisa...",
|
||||
"prompt.placeholder.summarizeComments": "Resumir comentários…",
|
||||
@@ -572,7 +572,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "Tema",
|
||||
"settings.general.row.theme.description": "Personalize como o OpenCode é tematizado.",
|
||||
"settings.general.row.font.title": "Fonte de código",
|
||||
"settings.general.row.font.description": "Personalize a fonte usada em blocos de código e terminais",
|
||||
"settings.general.row.font.description": "Personalize a fonte usada em blocos de código",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "Fonte da interface",
|
||||
"settings.general.row.uiFont.description": "Personalize a fonte usada em toda a interface",
|
||||
"settings.general.row.followup.title": "Comportamento de acompanhamento",
|
||||
@@ -588,6 +590,9 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.title": "Expandir partes da ferramenta de edição",
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"Mostrar partes das ferramentas de edição, escrita e patch expandidas por padrão na linha do tempo",
|
||||
"settings.general.row.showSessionProgressBar.title": "Mostrar barra de progresso da sessão",
|
||||
"settings.general.row.showSessionProgressBar.description":
|
||||
"Exibir a barra de progresso animada no topo da sessão quando o agente estiver trabalhando",
|
||||
"settings.general.row.wayland.title": "Usar Wayland nativo",
|
||||
"settings.general.row.wayland.description": "Desabilitar fallback X11 no Wayland. Requer reinicialização.",
|
||||
"settings.general.row.wayland.tooltip":
|
||||
|
||||
@@ -228,7 +228,7 @@ export const dict = {
|
||||
"common.default": "Podrazumijevano",
|
||||
"common.attachment": "prilog",
|
||||
|
||||
"prompt.placeholder.shell": "Unesi shell naredbu...",
|
||||
"prompt.placeholder.shell": "Unesi shell naredbu... {{example}}",
|
||||
"prompt.placeholder.normal": 'Pitaj bilo šta... "{{example}}"',
|
||||
"prompt.placeholder.simple": "Pitaj bilo šta...",
|
||||
"prompt.placeholder.summarizeComments": "Sažmi komentare…",
|
||||
@@ -637,7 +637,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "Tema",
|
||||
"settings.general.row.theme.description": "Prilagodi temu OpenCode-a.",
|
||||
"settings.general.row.font.title": "Font za kod",
|
||||
"settings.general.row.font.description": "Prilagodi font koji se koristi u blokovima koda i terminalima",
|
||||
"settings.general.row.font.description": "Prilagodi font koji se koristi u blokovima koda",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "UI font",
|
||||
"settings.general.row.uiFont.description": "Prilagodi font koji se koristi u cijelom interfejsu",
|
||||
"settings.general.row.followup.title": "Ponašanje nadovezivanja",
|
||||
@@ -653,6 +655,9 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.title": "Proširi dijelove alata za uređivanje",
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"Prikaži dijelove alata za uređivanje, pisanje i patch podrazumijevano proširene na vremenskoj traci",
|
||||
"settings.general.row.showSessionProgressBar.title": "Prikaži traku napretka sesije",
|
||||
"settings.general.row.showSessionProgressBar.description":
|
||||
"Prikaži animiranu traku napretka na vrhu sesije kada agent radi",
|
||||
"settings.general.row.wayland.title": "Koristi nativni Wayland",
|
||||
"settings.general.row.wayland.description": "Onemogući X11 fallback na Waylandu. Zahtijeva restart.",
|
||||
"settings.general.row.wayland.tooltip":
|
||||
|
||||
@@ -226,7 +226,7 @@ export const dict = {
|
||||
"common.default": "Standard",
|
||||
"common.attachment": "vedhæftning",
|
||||
|
||||
"prompt.placeholder.shell": "Indtast shell-kommando...",
|
||||
"prompt.placeholder.shell": "Indtast shell-kommando... {{example}}",
|
||||
"prompt.placeholder.normal": 'Spørg om hvad som helst... "{{example}}"',
|
||||
"prompt.placeholder.simple": "Spørg om hvad som helst...",
|
||||
"prompt.placeholder.summarizeComments": "Opsummér kommentarer…",
|
||||
@@ -632,7 +632,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "Tema",
|
||||
"settings.general.row.theme.description": "Tilpas hvordan OpenCode er temabestemt.",
|
||||
"settings.general.row.font.title": "Kode-skrifttype",
|
||||
"settings.general.row.font.description": "Tilpas skrifttypen, der bruges i kodeblokke og terminaler",
|
||||
"settings.general.row.font.description": "Tilpas skrifttypen, der bruges i kodeblokke",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "UI-skrifttype",
|
||||
"settings.general.row.uiFont.description": "Tilpas skrifttypen, der bruges i hele brugerfladen",
|
||||
"settings.general.row.followup.title": "Opfølgningsadfærd",
|
||||
@@ -647,6 +649,9 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.title": "Udvid edit-værktøjsdele",
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"Vis edit-, write- og patch-værktøjsdele udvidet som standard i tidslinjen",
|
||||
"settings.general.row.showSessionProgressBar.title": "Vis sessionens fremdriftslinje",
|
||||
"settings.general.row.showSessionProgressBar.description":
|
||||
"Vis den animerede fremdriftslinje øverst i sessionen, når agenten arbejder",
|
||||
"settings.general.row.wayland.title": "Brug native Wayland",
|
||||
"settings.general.row.wayland.description": "Deaktiver X11-fallback på Wayland. Kræver genstart.",
|
||||
"settings.general.row.wayland.tooltip":
|
||||
|
||||
@@ -215,7 +215,7 @@ export const dict = {
|
||||
"common.saving": "Speichert...",
|
||||
"common.default": "Standard",
|
||||
"common.attachment": "Anhang",
|
||||
"prompt.placeholder.shell": "Shell-Befehl eingeben...",
|
||||
"prompt.placeholder.shell": "Shell-Befehl eingeben... {{example}}",
|
||||
"prompt.placeholder.normal": 'Fragen Sie alles... "{{example}}"',
|
||||
"prompt.placeholder.simple": "Fragen Sie alles...",
|
||||
"prompt.placeholder.summarizeComments": "Kommentare zusammenfassen…",
|
||||
@@ -582,7 +582,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "Thema",
|
||||
"settings.general.row.theme.description": "Das Thema von OpenCode anpassen.",
|
||||
"settings.general.row.font.title": "Code-Schriftart",
|
||||
"settings.general.row.font.description": "Die in Codeblöcken und Terminals verwendete Schriftart anpassen",
|
||||
"settings.general.row.font.description": "Die in Codeblöcken verwendete Schriftart anpassen",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "UI-Schriftart",
|
||||
"settings.general.row.uiFont.description": "Die im gesamten Interface verwendete Schriftart anpassen",
|
||||
"settings.general.row.followup.title": "Verhalten bei Folgefragen",
|
||||
@@ -599,6 +601,9 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.title": "Edit-Tool-Abschnitte ausklappen",
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"Edit-, Write- und Patch-Tool-Abschnitte standardmäßig in der Timeline ausgeklappt anzeigen",
|
||||
"settings.general.row.showSessionProgressBar.title": "Sitzungsfortschrittsleiste anzeigen",
|
||||
"settings.general.row.showSessionProgressBar.description":
|
||||
"Die animierte Fortschrittsleiste oben in der Sitzung anzeigen, wenn der Agent arbeitet",
|
||||
"settings.general.row.wayland.title": "Natives Wayland verwenden",
|
||||
"settings.general.row.wayland.description": "X11-Fallback unter Wayland deaktivieren. Erfordert Neustart.",
|
||||
"settings.general.row.wayland.tooltip":
|
||||
|
||||
@@ -230,7 +230,7 @@ export const dict = {
|
||||
"common.default": "Default",
|
||||
"common.attachment": "attachment",
|
||||
|
||||
"prompt.placeholder.shell": "Enter shell command...",
|
||||
"prompt.placeholder.shell": "Enter shell command... {{example}}",
|
||||
"prompt.placeholder.normal": 'Ask anything... "{{example}}"',
|
||||
"prompt.placeholder.simple": "Ask anything...",
|
||||
"prompt.placeholder.summarizeComments": "Summarize comments…",
|
||||
@@ -719,6 +719,7 @@ export const dict = {
|
||||
"settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
|
||||
|
||||
"settings.general.section.appearance": "Appearance",
|
||||
"settings.general.section.advanced": "Advanced",
|
||||
"settings.general.section.notifications": "System notifications",
|
||||
"settings.general.section.updates": "Updates",
|
||||
"settings.general.section.sounds": "Sound effects",
|
||||
@@ -734,13 +735,25 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "Theme",
|
||||
"settings.general.row.theme.description": "Customise how OpenCode is themed.",
|
||||
"settings.general.row.font.title": "Code Font",
|
||||
"settings.general.row.font.description": "Customise the font used in code blocks and terminals",
|
||||
"settings.general.row.font.description": "Customise the font used in code blocks",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "UI Font",
|
||||
"settings.general.row.uiFont.description": "Customise the font used throughout the interface",
|
||||
"settings.general.row.followup.title": "Follow-up behavior",
|
||||
"settings.general.row.followup.description": "Choose whether follow-up prompts steer immediately or wait in a queue",
|
||||
"settings.general.row.followup.option.queue": "Queue",
|
||||
"settings.general.row.followup.option.steer": "Steer",
|
||||
"settings.general.row.showFileTree.title": "File tree",
|
||||
"settings.general.row.showFileTree.description": "Show the file tree toggle and panel in desktop sessions",
|
||||
"settings.general.row.showNavigation.title": "Navigation controls",
|
||||
"settings.general.row.showNavigation.description": "Show the back and forward buttons in the desktop title bar",
|
||||
"settings.general.row.showSearch.title": "Command palette",
|
||||
"settings.general.row.showSearch.description": "Show the search and command palette button in the desktop title bar",
|
||||
"settings.general.row.showTerminal.title": "Terminal",
|
||||
"settings.general.row.showTerminal.description": "Show the terminal button in the desktop title bar",
|
||||
"settings.general.row.showStatus.title": "Server status",
|
||||
"settings.general.row.showStatus.description": "Show the server status button in the desktop title bar",
|
||||
"settings.general.row.reasoningSummaries.title": "Show reasoning summaries",
|
||||
"settings.general.row.reasoningSummaries.description": "Display model reasoning summaries in the timeline",
|
||||
"settings.general.row.shellToolPartsExpanded.title": "Expand shell tool parts",
|
||||
@@ -749,6 +762,9 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.title": "Expand edit tool parts",
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"Show edit, write, and patch tool parts expanded by default in the timeline",
|
||||
"settings.general.row.showSessionProgressBar.title": "Show session progress bar",
|
||||
"settings.general.row.showSessionProgressBar.description":
|
||||
"Display the animated progress bar at the top of the session when the agent is working",
|
||||
|
||||
"settings.general.row.wayland.title": "Use native Wayland",
|
||||
"settings.general.row.wayland.description": "Disable X11 fallback on Wayland. Requires restart.",
|
||||
|
||||
@@ -227,7 +227,7 @@ export const dict = {
|
||||
"common.default": "Predeterminado",
|
||||
"common.attachment": "adjunto",
|
||||
|
||||
"prompt.placeholder.shell": "Introduce comando de shell...",
|
||||
"prompt.placeholder.shell": "Introduce comando de shell... {{example}}",
|
||||
"prompt.placeholder.normal": 'Pregunta cualquier cosa... "{{example}}"',
|
||||
"prompt.placeholder.simple": "Pregunta cualquier cosa...",
|
||||
"prompt.placeholder.summarizeComments": "Resumir comentarios…",
|
||||
@@ -640,7 +640,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "Tema",
|
||||
"settings.general.row.theme.description": "Personaliza el tema de OpenCode.",
|
||||
"settings.general.row.font.title": "Fuente de código",
|
||||
"settings.general.row.font.description": "Personaliza la fuente usada en bloques de código y terminales",
|
||||
"settings.general.row.font.description": "Personaliza la fuente usada en bloques de código",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "Fuente de la interfaz",
|
||||
"settings.general.row.uiFont.description": "Personaliza la fuente usada en toda la interfaz",
|
||||
"settings.general.row.followup.title": "Comportamiento de seguimiento",
|
||||
@@ -657,6 +659,9 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.title": "Expandir partes de la herramienta de edición",
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"Mostrar las partes de las herramientas de edición, escritura y parcheado expandidas por defecto en la línea de tiempo",
|
||||
"settings.general.row.showSessionProgressBar.title": "Mostrar barra de progreso de la sesión",
|
||||
"settings.general.row.showSessionProgressBar.description":
|
||||
"Mostrar la barra de progreso animada en la parte superior de la sesión cuando el agente esté trabajando",
|
||||
"settings.general.row.wayland.title": "Usar Wayland nativo",
|
||||
"settings.general.row.wayland.description": "Deshabilitar fallback a X11 en Wayland. Requiere reinicio.",
|
||||
"settings.general.row.wayland.tooltip":
|
||||
|
||||
@@ -210,7 +210,7 @@ export const dict = {
|
||||
"common.saving": "Enregistrement...",
|
||||
"common.default": "Défaut",
|
||||
"common.attachment": "pièce jointe",
|
||||
"prompt.placeholder.shell": "Entrez une commande shell...",
|
||||
"prompt.placeholder.shell": "Entrez une commande shell... {{example}}",
|
||||
"prompt.placeholder.normal": 'Demandez n\'importe quoi... "{{example}}"',
|
||||
"prompt.placeholder.simple": "Demandez n'importe quoi...",
|
||||
"prompt.placeholder.summarizeComments": "Résumer les commentaires…",
|
||||
@@ -579,7 +579,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "Thème",
|
||||
"settings.general.row.theme.description": "Personnaliser le thème d'OpenCode.",
|
||||
"settings.general.row.font.title": "Police de code",
|
||||
"settings.general.row.font.description": "Personnaliser la police utilisée dans les blocs de code et les terminaux",
|
||||
"settings.general.row.font.description": "Personnaliser la police utilisée dans les blocs de code",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "Police de l'interface",
|
||||
"settings.general.row.uiFont.description": "Personnaliser la police utilisée dans toute l'interface",
|
||||
"settings.general.row.followup.title": "Comportement de suivi",
|
||||
@@ -596,6 +598,9 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.title": "Développer les parties de l'outil edit",
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"Afficher les parties des outils edit, write et patch développées par défaut dans la chronologie",
|
||||
"settings.general.row.showSessionProgressBar.title": "Afficher la barre de progression de la session",
|
||||
"settings.general.row.showSessionProgressBar.description":
|
||||
"Afficher la barre de progression animée en haut de la session lorsque l'agent travaille",
|
||||
"settings.general.row.wayland.title": "Utiliser Wayland natif",
|
||||
"settings.general.row.wayland.description": "Désactiver le repli X11 sur Wayland. Nécessite un redémarrage.",
|
||||
"settings.general.row.wayland.tooltip":
|
||||
|
||||
@@ -209,7 +209,7 @@ export const dict = {
|
||||
"common.saving": "保存中...",
|
||||
"common.default": "デフォルト",
|
||||
"common.attachment": "添付ファイル",
|
||||
"prompt.placeholder.shell": "シェルコマンドを入力...",
|
||||
"prompt.placeholder.shell": "シェルコマンドを入力... {{example}}",
|
||||
"prompt.placeholder.normal": '何でも聞いてください... "{{example}}"',
|
||||
"prompt.placeholder.simple": "何でも聞いてください...",
|
||||
"prompt.placeholder.summarizeComments": "コメントを要約…",
|
||||
@@ -569,7 +569,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "テーマ",
|
||||
"settings.general.row.theme.description": "OpenCodeのテーマをカスタマイズします。",
|
||||
"settings.general.row.font.title": "コードフォント",
|
||||
"settings.general.row.font.description": "コードブロックとターミナルで使用するフォントをカスタマイズします",
|
||||
"settings.general.row.font.description": "コードブロックで使用するフォントをカスタマイズします",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "UIフォント",
|
||||
"settings.general.row.uiFont.description": "インターフェース全体で使用するフォントをカスタマイズします",
|
||||
"settings.general.row.followup.title": "フォローアップの動作",
|
||||
@@ -585,6 +587,9 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.title": "edit ツールパーツを展開",
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"タイムラインで edit、write、patch ツールパーツをデフォルトで展開して表示します",
|
||||
"settings.general.row.showSessionProgressBar.title": "セッション進行状況バーを表示",
|
||||
"settings.general.row.showSessionProgressBar.description":
|
||||
"エージェントの作業中に、セッション上部にアニメーション付きの進行状況バーを表示します",
|
||||
"settings.general.row.wayland.title": "ネイティブWaylandを使用",
|
||||
"settings.general.row.wayland.description": "WaylandでのX11フォールバックを無効にします。再起動が必要です。",
|
||||
"settings.general.row.wayland.tooltip":
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
import { dict as en } from "./en"
|
||||
|
||||
type Keys = keyof typeof en
|
||||
|
||||
export const dict = {
|
||||
"command.category.suggested": "추천",
|
||||
"command.category.view": "보기",
|
||||
@@ -213,7 +209,7 @@ export const dict = {
|
||||
"common.saving": "저장 중...",
|
||||
"common.default": "기본값",
|
||||
"common.attachment": "첨부 파일",
|
||||
"prompt.placeholder.shell": "셸 명령어 입력...",
|
||||
"prompt.placeholder.shell": "셸 명령어 입력... {{example}}",
|
||||
"prompt.placeholder.normal": '무엇이든 물어보세요... "{{example}}"',
|
||||
"prompt.placeholder.simple": "무엇이든 물어보세요...",
|
||||
"prompt.placeholder.summarizeComments": "댓글 요약…",
|
||||
@@ -570,7 +566,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "테마",
|
||||
"settings.general.row.theme.description": "OpenCode 테마 사용자 지정",
|
||||
"settings.general.row.font.title": "코드 글꼴",
|
||||
"settings.general.row.font.description": "코드 블록과 터미널에 사용되는 글꼴을 사용자 지정",
|
||||
"settings.general.row.font.description": "코드 블록에 사용되는 글꼴을 사용자 지정",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "UI 글꼴",
|
||||
"settings.general.row.uiFont.description": "인터페이스 전반에 사용되는 글꼴을 사용자 지정",
|
||||
"settings.general.row.followup.title": "후속 조치 동작",
|
||||
@@ -585,6 +583,9 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.title": "edit 도구 파트 펼치기",
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"타임라인에서 기본적으로 edit, write, patch 도구 파트를 펼친 상태로 표시합니다",
|
||||
"settings.general.row.showSessionProgressBar.title": "세션 진행 표시줄 표시",
|
||||
"settings.general.row.showSessionProgressBar.description":
|
||||
"에이전트가 작업 중일 때 세션 상단에 애니메이션 진행 표시줄을 표시합니다",
|
||||
"settings.general.row.wayland.title": "네이티브 Wayland 사용",
|
||||
"settings.general.row.wayland.description": "Wayland에서 X11 폴백을 비활성화합니다. 다시 시작해야 합니다.",
|
||||
"settings.general.row.wayland.tooltip":
|
||||
|
||||
@@ -230,7 +230,7 @@ export const dict = {
|
||||
"common.default": "Standard",
|
||||
"common.attachment": "vedlegg",
|
||||
|
||||
"prompt.placeholder.shell": "Skriv inn shell-kommando...",
|
||||
"prompt.placeholder.shell": "Skriv inn shell-kommando... {{example}}",
|
||||
"prompt.placeholder.normal": 'Spør om hva som helst... "{{example}}"',
|
||||
"prompt.placeholder.simple": "Spør om hva som helst...",
|
||||
"prompt.placeholder.summarizeComments": "Oppsummer kommentarer…",
|
||||
@@ -640,7 +640,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "Tema",
|
||||
"settings.general.row.theme.description": "Tilpass hvordan OpenCode er tematisert.",
|
||||
"settings.general.row.font.title": "Kodefont",
|
||||
"settings.general.row.font.description": "Tilpass skrifttypen som brukes i kodeblokker og terminaler",
|
||||
"settings.general.row.font.description": "Tilpass skrifttypen som brukes i kodeblokker",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "UI-skrift",
|
||||
"settings.general.row.uiFont.description": "Tilpass skrifttypen som brukes i hele grensesnittet",
|
||||
"settings.general.row.followup.title": "Oppfølgingsadferd",
|
||||
@@ -654,6 +656,9 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.title": "Utvid edit-verktøydeler",
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"Vis edit-, write- og patch-verktøydeler utvidet som standard i tidslinjen",
|
||||
"settings.general.row.showSessionProgressBar.title": "Vis fremdriftslinje for sesjonen",
|
||||
"settings.general.row.showSessionProgressBar.description":
|
||||
"Vis den animerte fremdriftslinjen øverst i sesjonen når agenten jobber",
|
||||
"settings.general.row.wayland.title": "Bruk innebygd Wayland",
|
||||
"settings.general.row.wayland.description": "Deaktiver X11-fallback på Wayland. Krever omstart.",
|
||||
"settings.general.row.wayland.tooltip":
|
||||
|
||||
@@ -211,7 +211,7 @@ export const dict = {
|
||||
"common.saving": "Zapisywanie...",
|
||||
"common.default": "Domyślny",
|
||||
"common.attachment": "załącznik",
|
||||
"prompt.placeholder.shell": "Wpisz polecenie terminala...",
|
||||
"prompt.placeholder.shell": "Wpisz polecenie terminala... {{example}}",
|
||||
"prompt.placeholder.normal": 'Zapytaj o cokolwiek... "{{example}}"',
|
||||
"prompt.placeholder.simple": "Zapytaj o cokolwiek...",
|
||||
"prompt.placeholder.summarizeComments": "Podsumuj komentarze…",
|
||||
@@ -571,7 +571,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "Motyw",
|
||||
"settings.general.row.theme.description": "Dostosuj motyw OpenCode.",
|
||||
"settings.general.row.font.title": "Czcionka kodu",
|
||||
"settings.general.row.font.description": "Dostosuj czcionkę używaną w blokach kodu i terminalach",
|
||||
"settings.general.row.font.description": "Dostosuj czcionkę używaną w blokach kodu",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "Czcionka interfejsu",
|
||||
"settings.general.row.uiFont.description": "Dostosuj czcionkę używaną w całym interfejsie",
|
||||
"settings.general.row.followup.title": "Zachowanie kontynuacji",
|
||||
@@ -586,6 +588,9 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.title": "Rozwijaj elementy narzędzia edit",
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"Domyślnie pokazuj rozwinięte elementy narzędzi edit, write i patch na osi czasu",
|
||||
"settings.general.row.showSessionProgressBar.title": "Pokazuj pasek postępu sesji",
|
||||
"settings.general.row.showSessionProgressBar.description":
|
||||
"Wyświetlaj animowany pasek postępu u góry sesji, gdy agent pracuje",
|
||||
"settings.general.row.wayland.title": "Użyj natywnego Wayland",
|
||||
"settings.general.row.wayland.description": "Wyłącz fallback X11 na Wayland. Wymaga restartu.",
|
||||
"settings.general.row.wayland.tooltip":
|
||||
|
||||
@@ -227,7 +227,7 @@ export const dict = {
|
||||
"common.default": "По умолчанию",
|
||||
"common.attachment": "вложение",
|
||||
|
||||
"prompt.placeholder.shell": "Введите команду оболочки...",
|
||||
"prompt.placeholder.shell": "Введите команду оболочки... {{example}}",
|
||||
"prompt.placeholder.normal": 'Спросите что угодно... "{{example}}"',
|
||||
"prompt.placeholder.simple": "Спросите что угодно...",
|
||||
"prompt.placeholder.summarizeComments": "Суммировать комментарии…",
|
||||
@@ -637,7 +637,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "Тема",
|
||||
"settings.general.row.theme.description": "Настройте оформление OpenCode.",
|
||||
"settings.general.row.font.title": "Шрифт кода",
|
||||
"settings.general.row.font.description": "Настройте шрифт, используемый в блоках кода и терминалах",
|
||||
"settings.general.row.font.description": "Настройте шрифт, используемый в блоках кода",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "Шрифт интерфейса",
|
||||
"settings.general.row.uiFont.description": "Настройте шрифт, используемый во всем интерфейсе",
|
||||
"settings.general.row.followup.title": "Поведение уточняющих вопросов",
|
||||
@@ -654,6 +656,9 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.title": "Разворачивать элементы инструмента edit",
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"Показывать элементы инструментов edit, write и patch в ленте развернутыми по умолчанию",
|
||||
"settings.general.row.showSessionProgressBar.title": "Показывать индикатор прогресса сессии",
|
||||
"settings.general.row.showSessionProgressBar.description":
|
||||
"Показывать анимированный индикатор прогресса вверху сессии, когда агент работает",
|
||||
"settings.general.row.wayland.title": "Использовать нативный Wayland",
|
||||
"settings.general.row.wayland.description": "Отключить X11 fallback на Wayland. Требуется перезапуск.",
|
||||
"settings.general.row.wayland.tooltip":
|
||||
|
||||
@@ -227,7 +227,7 @@ export const dict = {
|
||||
"common.default": "ค่าเริ่มต้น",
|
||||
"common.attachment": "ไฟล์แนบ",
|
||||
|
||||
"prompt.placeholder.shell": "ป้อนคำสั่งเชลล์...",
|
||||
"prompt.placeholder.shell": "ป้อนคำสั่งเชลล์... {{example}}",
|
||||
"prompt.placeholder.normal": 'ถามอะไรก็ได้... "{{example}}"',
|
||||
"prompt.placeholder.simple": "ถามอะไรก็ได้...",
|
||||
"prompt.placeholder.summarizeComments": "สรุปความคิดเห็น…",
|
||||
@@ -631,7 +631,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "ธีม",
|
||||
"settings.general.row.theme.description": "ปรับแต่งวิธีการที่ OpenCode มีธีม",
|
||||
"settings.general.row.font.title": "ฟอนต์โค้ด",
|
||||
"settings.general.row.font.description": "ปรับแต่งฟอนต์ที่ใช้ในบล็อกโค้ดและเทอร์มินัล",
|
||||
"settings.general.row.font.description": "ปรับแต่งฟอนต์ที่ใช้ในบล็อกโค้ด",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "ฟอนต์ UI",
|
||||
"settings.general.row.uiFont.description": "ปรับแต่งฟอนต์ที่ใช้ทั่วทั้งอินเทอร์เฟซ",
|
||||
"settings.general.row.followup.title": "พฤติกรรมการติดตามผล",
|
||||
@@ -645,6 +647,9 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.title": "ขยายส่วนเครื่องมือ edit",
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"แสดงส่วนเครื่องมือ edit, write และ patch แบบขยายตามค่าเริ่มต้นในไทม์ไลน์",
|
||||
"settings.general.row.showSessionProgressBar.title": "แสดงแถบความคืบหน้าของเซสชัน",
|
||||
"settings.general.row.showSessionProgressBar.description":
|
||||
"แสดงแถบความคืบหน้าแบบเคลื่อนไหวที่ด้านบนของเซสชันเมื่อเอเจนต์กำลังทำงาน",
|
||||
"settings.general.row.wayland.title": "ใช้ Wayland แบบเนทีฟ",
|
||||
"settings.general.row.wayland.description": "ปิดใช้งาน X11 fallback บน Wayland ต้องรีสตาร์ท",
|
||||
"settings.general.row.wayland.tooltip": "บน Linux ที่มีจอภาพรีเฟรชเรตแบบผสม Wayland แบบเนทีฟอาจเสถียรกว่า",
|
||||
|
||||
@@ -232,7 +232,7 @@ export const dict = {
|
||||
"common.default": "Varsayılan",
|
||||
"common.attachment": "ek",
|
||||
|
||||
"prompt.placeholder.shell": "Kabuk komutu girin...",
|
||||
"prompt.placeholder.shell": "Kabuk komutu girin... {{example}}",
|
||||
"prompt.placeholder.normal": 'Bir şeyler sorun... "{{example}}"',
|
||||
"prompt.placeholder.simple": "Bir şeyler sorun...",
|
||||
"prompt.placeholder.summarizeComments": "Yorumları özetle…",
|
||||
@@ -644,7 +644,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "Tema",
|
||||
"settings.general.row.theme.description": "OpenCode'un temasını özelleştirin.",
|
||||
"settings.general.row.font.title": "Kod Yazı Tipi",
|
||||
"settings.general.row.font.description": "Kod bloklarında ve terminallerde kullanılan yazı tipini özelleştirin",
|
||||
"settings.general.row.font.description": "Kod bloklarında kullanılan yazı tipini özelleştirin",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "Arayüz Yazı Tipi",
|
||||
"settings.general.row.uiFont.description": "Arayüz genelinde kullanılan yazı tipini özelleştirin",
|
||||
"settings.general.row.followup.title": "Takip davranışı",
|
||||
@@ -661,6 +663,10 @@ export const dict = {
|
||||
"settings.general.row.editToolPartsExpanded.description":
|
||||
"Zaman çizelgesinde düzenleme, yazma ve yama araç bileşenlerini varsayılan olarak genişletilmiş göster",
|
||||
|
||||
"settings.general.row.showSessionProgressBar.title": "Oturum ilerleme çubuğunu göster",
|
||||
"settings.general.row.showSessionProgressBar.description":
|
||||
"Ajan çalışırken oturumun üst kısmında animasyonlu ilerleme çubuğunu göster",
|
||||
|
||||
"settings.general.row.wayland.title": "Yerel Wayland kullan",
|
||||
"settings.general.row.wayland.description":
|
||||
"Wayland'da X11 geri dönüşünü devre dışı bırak. Yeniden başlatma gerektirir.",
|
||||
|
||||
@@ -249,7 +249,7 @@ export const dict = {
|
||||
"common.default": "默认",
|
||||
"common.attachment": "附件",
|
||||
|
||||
"prompt.placeholder.shell": "输入 shell 命令...",
|
||||
"prompt.placeholder.shell": "输入 shell 命令... {{example}}",
|
||||
"prompt.placeholder.normal": '随便问点什么... "{{example}}"',
|
||||
"prompt.placeholder.simple": "随便问点什么...",
|
||||
"prompt.placeholder.summarizeComments": "总结评论…",
|
||||
@@ -631,7 +631,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "主题",
|
||||
"settings.general.row.theme.description": "自定义 OpenCode 的主题。",
|
||||
"settings.general.row.font.title": "代码字体",
|
||||
"settings.general.row.font.description": "自定义代码块和终端使用的字体",
|
||||
"settings.general.row.font.description": "自定义代码块使用的字体",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "界面字体",
|
||||
"settings.general.row.uiFont.description": "自定义整个界面使用的字体",
|
||||
"settings.general.row.followup.title": "跟进消息行为",
|
||||
@@ -644,6 +646,8 @@ export const dict = {
|
||||
"settings.general.row.shellToolPartsExpanded.description": "默认在时间线中展开 shell 工具部分",
|
||||
"settings.general.row.editToolPartsExpanded.title": "展开编辑工具部分",
|
||||
"settings.general.row.editToolPartsExpanded.description": "默认在时间线中展开 edit、write 和 patch 工具部分",
|
||||
"settings.general.row.showSessionProgressBar.title": "显示会话进度条",
|
||||
"settings.general.row.showSessionProgressBar.description": "当智能体正在工作时,在会话顶部显示动画进度条",
|
||||
"settings.general.row.wayland.title": "使用原生 Wayland",
|
||||
"settings.general.row.wayland.description": "在 Wayland 上禁用 X11 回退。需要重启。",
|
||||
"settings.general.row.wayland.tooltip": "在混合刷新率显示器的 Linux 系统上,原生 Wayland 可能更稳定。",
|
||||
|
||||
@@ -227,7 +227,7 @@ export const dict = {
|
||||
"common.default": "預設",
|
||||
"common.attachment": "附件",
|
||||
|
||||
"prompt.placeholder.shell": "輸入 shell 命令...",
|
||||
"prompt.placeholder.shell": "輸入 shell 命令... {{example}}",
|
||||
"prompt.placeholder.normal": '隨便問點什麼... "{{example}}"',
|
||||
"prompt.placeholder.simple": "隨便問點什麼...",
|
||||
"prompt.placeholder.summarizeComments": "摘要評論…",
|
||||
@@ -626,7 +626,9 @@ export const dict = {
|
||||
"settings.general.row.theme.title": "主題",
|
||||
"settings.general.row.theme.description": "自訂 OpenCode 的主題。",
|
||||
"settings.general.row.font.title": "程式碼字型",
|
||||
"settings.general.row.font.description": "自訂程式碼區塊和終端機使用的字型",
|
||||
"settings.general.row.font.description": "自訂程式碼區塊使用的字型",
|
||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
||||
"settings.general.row.uiFont.title": "介面字型",
|
||||
"settings.general.row.uiFont.description": "自訂整個介面使用的字型",
|
||||
"settings.general.row.followup.title": "後續追問行為",
|
||||
@@ -640,6 +642,8 @@ export const dict = {
|
||||
"settings.general.row.shellToolPartsExpanded.description": "在時間軸中預設展開 shell 工具區塊",
|
||||
"settings.general.row.editToolPartsExpanded.title": "展開 edit 工具區塊",
|
||||
"settings.general.row.editToolPartsExpanded.description": "在時間軸中預設展開 edit、write 和 patch 工具區塊",
|
||||
"settings.general.row.showSessionProgressBar.title": "顯示工作階段進度列",
|
||||
"settings.general.row.showSessionProgressBar.description": "當代理程式正在運作時,在工作階段頂部顯示動畫進度列",
|
||||
"settings.general.row.wayland.title": "使用原生 Wayland",
|
||||
"settings.general.row.wayland.description": "在 Wayland 上停用 X11 後備模式。需要重新啟動。",
|
||||
"settings.general.row.wayland.tooltip": "在混合更新率螢幕的 Linux 系統上,原生 Wayland 可能更穩定。",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
@import "@opencode-ai/ui/styles/tailwind";
|
||||
|
||||
@font-face {
|
||||
font-family: "JetBrainsMono Nerd Font Mono";
|
||||
src: url("/assets/JetBrainsMonoNerdFontMono-Regular.woff2") format("woff2");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@layer components {
|
||||
@keyframes session-progress-whip {
|
||||
0% {
|
||||
@@ -66,4 +73,13 @@
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { DataProvider } from "@opencode-ai/ui/context"
|
||||
import { showToast } from "@opencode-ai/ui/toast"
|
||||
import { base64Encode } from "@opencode-ai/shared/util/encode"
|
||||
import { useLocation, useNavigate, useParams } from "@solidjs/router"
|
||||
import { createEffect, createMemo, type ParentProps, Show } from "solid-js"
|
||||
import { createEffect, createMemo, createResource, type ParentProps, Show } from "solid-js"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { LocalProvider } from "@/context/local"
|
||||
import { SDKProvider } from "@/context/sdk"
|
||||
@@ -23,11 +23,10 @@ function DirectoryDataProvider(props: ParentProps<{ directory: string }>) {
|
||||
navigate(`/${base64Encode(next)}${path}${location.search}${location.hash}`, { replace: true })
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
const id = params.id
|
||||
if (!id) return
|
||||
void sync.session.sync(id)
|
||||
})
|
||||
createResource(
|
||||
() => params.id,
|
||||
(id) => sync.session.sync(id),
|
||||
)
|
||||
|
||||
return (
|
||||
<DataProvider
|
||||
|
||||
@@ -244,10 +244,9 @@ export const ErrorPage: Component<ErrorPageProps> = (props) => {
|
||||
}
|
||||
|
||||
async function installUpdate() {
|
||||
if (!platform.update || !platform.restart) return
|
||||
if (!platform.updateAndRestart) return
|
||||
await platform
|
||||
.update()
|
||||
.then(() => platform.restart!())
|
||||
.updateAndRestart()
|
||||
.then(() => setStore("actionError", undefined))
|
||||
.catch((err) => {
|
||||
setStore("actionError", formatError(err, language.t))
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
type Accessor,
|
||||
} from "solid-js"
|
||||
import { makeEventListener } from "@solid-primitives/event-listener"
|
||||
import { useNavigate, useParams } from "@solidjs/router"
|
||||
import { useLocation, useNavigate, useParams } from "@solidjs/router"
|
||||
import { useLayout, LocalProject } from "@/context/layout"
|
||||
import { useGlobalSync } from "@/context/global-sync"
|
||||
import { Persist, persisted } from "@/utils/persist"
|
||||
@@ -127,14 +127,17 @@ export default function Layout(props: ParentProps) {
|
||||
const theme = useTheme()
|
||||
const language = useLanguage()
|
||||
const initialDirectory = decode64(params.dir)
|
||||
const location = useLocation()
|
||||
const route = createMemo(() => {
|
||||
const slug = params.dir
|
||||
if (!slug) return { slug, dir: "" }
|
||||
const dir = decode64(slug)
|
||||
if (!dir) return { slug, dir: "" }
|
||||
const store = globalSync.peek(dir, { bootstrap: false })
|
||||
return {
|
||||
slug,
|
||||
dir: globalSync.peek(dir, { bootstrap: false })[0].path.directory || dir,
|
||||
store,
|
||||
dir: store[0].path.directory || dir,
|
||||
}
|
||||
})
|
||||
const availableThemeEntries = createMemo(() => theme.ids().map((id) => [id, theme.themes()[id]] as const))
|
||||
@@ -363,7 +366,7 @@ export default function Layout(props: ParentProps) {
|
||||
|
||||
const useUpdatePolling = () =>
|
||||
onMount(() => {
|
||||
if (!platform.checkUpdate || !platform.update || !platform.restart) return
|
||||
if (!platform.checkUpdate || !platform.updateAndRestart) return
|
||||
|
||||
let toastId: number | undefined
|
||||
let interval: ReturnType<typeof setInterval> | undefined
|
||||
@@ -381,8 +384,7 @@ export default function Layout(props: ParentProps) {
|
||||
{
|
||||
label: language.t("toast.update.action.installRestart"),
|
||||
onClick: async () => {
|
||||
await platform.update!()
|
||||
await platform.restart!()
|
||||
await platform.updateAndRestart!()
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -704,7 +706,7 @@ export default function Layout(props: ParentProps) {
|
||||
|
||||
createEffect(() => {
|
||||
const active = new Set(visibleSessionDirs())
|
||||
for (const directory of [...prefetchedByDir.keys()]) {
|
||||
for (const directory of prefetchedByDir.keys()) {
|
||||
if (active.has(directory)) continue
|
||||
prefetchedByDir.delete(directory)
|
||||
}
|
||||
@@ -956,7 +958,7 @@ export default function Layout(props: ParentProps) {
|
||||
|
||||
// warm up child store to prevent flicker
|
||||
globalSync.child(target.worktree)
|
||||
openProject(target.worktree)
|
||||
void openProject(target.worktree)
|
||||
}
|
||||
|
||||
function navigateSessionByUnseen(offset: number) {
|
||||
@@ -1094,7 +1096,7 @@ export default function Layout(props: ParentProps) {
|
||||
disabled: !params.dir || !params.id,
|
||||
onSelect: () => {
|
||||
const session = currentSessions().find((s) => s.id === params.id)
|
||||
if (session) archiveSession(session)
|
||||
if (session) void archiveSession(session)
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1360,11 +1362,11 @@ export default function Layout(props: ParentProps) {
|
||||
if (!server.isLocal()) return
|
||||
|
||||
for (const directory of collectOpenProjectDeepLinks(urls)) {
|
||||
openProject(directory)
|
||||
void openProject(directory)
|
||||
}
|
||||
|
||||
for (const link of collectNewSessionDeepLinks(urls)) {
|
||||
openProject(link.directory, false)
|
||||
void openProject(link.directory, false)
|
||||
const slug = base64Encode(link.directory)
|
||||
if (link.prompt) {
|
||||
setSessionHandoff(slug, { prompt: link.prompt })
|
||||
@@ -1453,11 +1455,11 @@ export default function Layout(props: ParentProps) {
|
||||
function resolve(result: string | string[] | null) {
|
||||
if (Array.isArray(result)) {
|
||||
for (const directory of result) {
|
||||
openProject(directory, false)
|
||||
void openProject(directory, false)
|
||||
}
|
||||
navigateToProject(result[0])
|
||||
void navigateToProject(result[0])
|
||||
} else if (result) {
|
||||
openProject(result)
|
||||
void openProject(result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1825,7 +1827,7 @@ export default function Layout(props: ParentProps) {
|
||||
const next = new Set(dirs)
|
||||
for (const directory of next) {
|
||||
if (loadedSessionDirs.has(directory)) continue
|
||||
globalSync.project.loadSessions(directory)
|
||||
void globalSync.project.loadSessions(directory)
|
||||
}
|
||||
|
||||
loadedSessionDirs.clear()
|
||||
@@ -2100,196 +2102,198 @@ export default function Layout(props: ParentProps) {
|
||||
</Show>
|
||||
}
|
||||
>
|
||||
<>
|
||||
<div class="shrink-0 pl-1 py-1">
|
||||
<div class="group/project flex items-start justify-between gap-2 py-2 pl-2 pr-0">
|
||||
<div class="flex flex-col min-w-0">
|
||||
<InlineEditor
|
||||
id={`project:${projectId()}`}
|
||||
value={projectName}
|
||||
onSave={(next) => {
|
||||
const item = project()
|
||||
if (!item) return
|
||||
renameProject(item, next)
|
||||
}}
|
||||
class="text-14-medium text-text-strong truncate"
|
||||
displayClass="text-14-medium text-text-strong truncate"
|
||||
stopPropagation
|
||||
/>
|
||||
{(project) => (
|
||||
<>
|
||||
<div class="shrink-0 pl-1 py-1">
|
||||
<div class="group/project flex items-start justify-between gap-2 py-2 pl-2 pr-0">
|
||||
<div class="flex flex-col min-w-0">
|
||||
<InlineEditor
|
||||
id={`project:${projectId()}`}
|
||||
value={projectName}
|
||||
onSave={(next) => {
|
||||
const item = project()
|
||||
if (!item) return
|
||||
void renameProject(item, next)
|
||||
}}
|
||||
class="text-14-medium text-text-strong truncate"
|
||||
displayClass="text-14-medium text-text-strong truncate"
|
||||
stopPropagation
|
||||
/>
|
||||
|
||||
<Tooltip
|
||||
placement="bottom"
|
||||
gutter={2}
|
||||
value={worktree()}
|
||||
class="shrink-0"
|
||||
contentStyle={{
|
||||
"max-width": "640px",
|
||||
transform: "translate3d(52px, 0, 0)",
|
||||
}}
|
||||
>
|
||||
<span class="text-12-regular text-text-base truncate select-text">
|
||||
{worktree().replace(homedir(), "~")}
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
placement="bottom"
|
||||
gutter={2}
|
||||
value={worktree()}
|
||||
class="shrink-0"
|
||||
contentStyle={{
|
||||
"max-width": "640px",
|
||||
transform: "translate3d(52px, 0, 0)",
|
||||
}}
|
||||
>
|
||||
<span class="text-12-regular text-text-base truncate select-text">
|
||||
{worktree().replace(homedir(), "~")}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<DropdownMenu modal={!sidebarHovering()}>
|
||||
<DropdownMenu.Trigger
|
||||
as={IconButton}
|
||||
icon="dot-grid"
|
||||
variant="ghost"
|
||||
data-action="project-menu"
|
||||
data-project={slug()}
|
||||
class="shrink-0 size-6 rounded-md transition-opacity data-[expanded]:bg-surface-base-active"
|
||||
classList={{
|
||||
"opacity-100": panelProps.mobile || merged(),
|
||||
"opacity-0 group-hover/project:opacity-100 group-focus-within/project:opacity-100 data-[expanded]:opacity-100":
|
||||
!panelProps.mobile && !merged(),
|
||||
}}
|
||||
aria-label={language.t("common.moreOptions")}
|
||||
/>
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content class="mt-1">
|
||||
<DropdownMenu.Item
|
||||
onSelect={() => {
|
||||
const item = project()
|
||||
if (!item) return
|
||||
showEditProjectDialog(item)
|
||||
}}
|
||||
>
|
||||
<DropdownMenu.ItemLabel>{language.t("common.edit")}</DropdownMenu.ItemLabel>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
data-action="project-workspaces-toggle"
|
||||
data-project={slug()}
|
||||
disabled={!canToggle()}
|
||||
onSelect={() => {
|
||||
const item = project()
|
||||
if (!item) return
|
||||
toggleProjectWorkspaces(item)
|
||||
}}
|
||||
>
|
||||
<DropdownMenu.ItemLabel>
|
||||
{workspacesEnabled()
|
||||
? language.t("sidebar.workspaces.disable")
|
||||
: language.t("sidebar.workspaces.enable")}
|
||||
</DropdownMenu.ItemLabel>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
data-action="project-clear-notifications"
|
||||
data-project={slug()}
|
||||
disabled={unseenCount() === 0}
|
||||
onSelect={clearNotifications}
|
||||
>
|
||||
<DropdownMenu.ItemLabel>
|
||||
{language.t("sidebar.project.clearNotifications")}
|
||||
</DropdownMenu.ItemLabel>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item
|
||||
data-action="project-close-menu"
|
||||
data-project={slug()}
|
||||
onSelect={() => {
|
||||
const dir = worktree()
|
||||
if (!dir) return
|
||||
closeProject(dir)
|
||||
}}
|
||||
>
|
||||
<DropdownMenu.ItemLabel>{language.t("common.close")}</DropdownMenu.ItemLabel>
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
||||
<DropdownMenu modal={!sidebarHovering()}>
|
||||
<DropdownMenu.Trigger
|
||||
as={IconButton}
|
||||
icon="dot-grid"
|
||||
variant="ghost"
|
||||
data-action="project-menu"
|
||||
data-project={slug()}
|
||||
class="shrink-0 size-6 rounded-md transition-opacity data-[expanded]:bg-surface-base-active"
|
||||
classList={{
|
||||
"opacity-100": panelProps.mobile || merged(),
|
||||
"opacity-0 group-hover/project:opacity-100 group-focus-within/project:opacity-100 data-[expanded]:opacity-100":
|
||||
!panelProps.mobile && !merged(),
|
||||
}}
|
||||
aria-label={language.t("common.moreOptions")}
|
||||
/>
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content class="mt-1">
|
||||
<DropdownMenu.Item
|
||||
onSelect={() => {
|
||||
const item = project()
|
||||
if (!item) return
|
||||
showEditProjectDialog(item)
|
||||
}}
|
||||
>
|
||||
<DropdownMenu.ItemLabel>{language.t("common.edit")}</DropdownMenu.ItemLabel>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
data-action="project-workspaces-toggle"
|
||||
data-project={slug()}
|
||||
disabled={!canToggle()}
|
||||
onSelect={() => {
|
||||
const item = project()
|
||||
if (!item) return
|
||||
toggleProjectWorkspaces(item)
|
||||
}}
|
||||
>
|
||||
<DropdownMenu.ItemLabel>
|
||||
{workspacesEnabled()
|
||||
? language.t("sidebar.workspaces.disable")
|
||||
: language.t("sidebar.workspaces.enable")}
|
||||
</DropdownMenu.ItemLabel>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
data-action="project-clear-notifications"
|
||||
data-project={slug()}
|
||||
disabled={unseenCount() === 0}
|
||||
onSelect={clearNotifications}
|
||||
>
|
||||
<DropdownMenu.ItemLabel>
|
||||
{language.t("sidebar.project.clearNotifications")}
|
||||
</DropdownMenu.ItemLabel>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item
|
||||
data-action="project-close-menu"
|
||||
data-project={slug()}
|
||||
onSelect={() => {
|
||||
const dir = worktree()
|
||||
if (!dir) return
|
||||
closeProject(dir)
|
||||
}}
|
||||
>
|
||||
<DropdownMenu.ItemLabel>{language.t("common.close")}</DropdownMenu.ItemLabel>
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 min-h-0 flex flex-col">
|
||||
<Show
|
||||
when={workspacesEnabled()}
|
||||
fallback={
|
||||
<div class="flex-1 min-h-0 flex flex-col">
|
||||
<Show
|
||||
when={workspacesEnabled()}
|
||||
fallback={
|
||||
<>
|
||||
<div class="shrink-0 py-4">
|
||||
<Button
|
||||
size="large"
|
||||
icon="new-session"
|
||||
class="w-full"
|
||||
onClick={() => {
|
||||
const dir = worktree()
|
||||
if (!dir) return
|
||||
navigateWithSidebarReset(`/${base64Encode(dir)}/session`)
|
||||
}}
|
||||
>
|
||||
{language.t("command.session.new")}
|
||||
</Button>
|
||||
</div>
|
||||
<div class="flex-1 min-h-0">
|
||||
<LocalWorkspace
|
||||
ctx={workspaceSidebarCtx}
|
||||
project={project()}
|
||||
sortNow={sortNow}
|
||||
mobile={panelProps.mobile}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<>
|
||||
<div class="shrink-0 py-4">
|
||||
<Button
|
||||
size="large"
|
||||
icon="new-session"
|
||||
icon="plus-small"
|
||||
class="w-full"
|
||||
onClick={() => {
|
||||
const dir = worktree()
|
||||
if (!dir) return
|
||||
navigateWithSidebarReset(`/${base64Encode(dir)}/session`)
|
||||
const item = project()
|
||||
if (!item) return
|
||||
void createWorkspace(item)
|
||||
}}
|
||||
>
|
||||
{language.t("command.session.new")}
|
||||
{language.t("workspace.new")}
|
||||
</Button>
|
||||
</div>
|
||||
<div class="flex-1 min-h-0">
|
||||
<LocalWorkspace
|
||||
ctx={workspaceSidebarCtx}
|
||||
project={project()!}
|
||||
sortNow={sortNow}
|
||||
mobile={panelProps.mobile}
|
||||
/>
|
||||
<div class="relative flex-1 min-h-0">
|
||||
<DragDropProvider
|
||||
onDragStart={handleWorkspaceDragStart}
|
||||
onDragEnd={handleWorkspaceDragEnd}
|
||||
onDragOver={handleWorkspaceDragOver}
|
||||
collisionDetector={closestCenter}
|
||||
>
|
||||
<DragDropSensors />
|
||||
<ConstrainDragXAxis />
|
||||
<div
|
||||
ref={(el) => {
|
||||
if (!panelProps.mobile) scrollContainerRef = el
|
||||
}}
|
||||
class="size-full flex flex-col py-2 gap-4 overflow-y-auto no-scrollbar [overflow-anchor:none]"
|
||||
>
|
||||
<SortableProvider ids={workspaces()}>
|
||||
<For each={workspaces()}>
|
||||
{(directory) => (
|
||||
<SortableWorkspace
|
||||
ctx={workspaceSidebarCtx}
|
||||
directory={directory}
|
||||
project={project()}
|
||||
sortNow={sortNow}
|
||||
mobile={panelProps.mobile}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
</SortableProvider>
|
||||
</div>
|
||||
<DragOverlay>
|
||||
<WorkspaceDragOverlay
|
||||
sidebarProject={sidebarProject}
|
||||
activeWorkspace={() => store.activeWorkspace}
|
||||
workspaceLabel={workspaceLabel}
|
||||
/>
|
||||
</DragOverlay>
|
||||
</DragDropProvider>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<>
|
||||
<div class="shrink-0 py-4">
|
||||
<Button
|
||||
size="large"
|
||||
icon="plus-small"
|
||||
class="w-full"
|
||||
onClick={() => {
|
||||
const item = project()
|
||||
if (!item) return
|
||||
createWorkspace(item)
|
||||
}}
|
||||
>
|
||||
{language.t("workspace.new")}
|
||||
</Button>
|
||||
</div>
|
||||
<div class="relative flex-1 min-h-0">
|
||||
<DragDropProvider
|
||||
onDragStart={handleWorkspaceDragStart}
|
||||
onDragEnd={handleWorkspaceDragEnd}
|
||||
onDragOver={handleWorkspaceDragOver}
|
||||
collisionDetector={closestCenter}
|
||||
>
|
||||
<DragDropSensors />
|
||||
<ConstrainDragXAxis />
|
||||
<div
|
||||
ref={(el) => {
|
||||
if (!panelProps.mobile) scrollContainerRef = el
|
||||
}}
|
||||
class="size-full flex flex-col py-2 gap-4 overflow-y-auto no-scrollbar [overflow-anchor:none]"
|
||||
>
|
||||
<SortableProvider ids={workspaces()}>
|
||||
<For each={workspaces()}>
|
||||
{(directory) => (
|
||||
<SortableWorkspace
|
||||
ctx={workspaceSidebarCtx}
|
||||
directory={directory}
|
||||
project={project()!}
|
||||
sortNow={sortNow}
|
||||
mobile={panelProps.mobile}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
</SortableProvider>
|
||||
</div>
|
||||
<DragOverlay>
|
||||
<WorkspaceDragOverlay
|
||||
sidebarProject={sidebarProject}
|
||||
activeWorkspace={() => store.activeWorkspace}
|
||||
workspaceLabel={workspaceLabel}
|
||||
/>
|
||||
</DragOverlay>
|
||||
</DragDropProvider>
|
||||
</div>
|
||||
</>
|
||||
</Show>
|
||||
</div>
|
||||
</>
|
||||
</Show>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Show>
|
||||
|
||||
<div
|
||||
@@ -2355,6 +2359,7 @@ export default function Layout(props: ParentProps) {
|
||||
|
||||
return (
|
||||
<div class="relative bg-background-base flex-1 min-h-0 min-w-0 flex flex-col select-none [&_input]:select-text [&_textarea]:select-text [&_[contenteditable]]:select-text">
|
||||
{autoselecting() ?? ""}
|
||||
<Titlebar />
|
||||
<div class="flex-1 min-h-0 min-w-0 flex">
|
||||
<div class="flex-1 min-h-0 relative">
|
||||
|
||||
@@ -31,7 +31,7 @@ function sortSessions(now: number) {
|
||||
const isRootVisibleSession = (session: Session, directory: string) =>
|
||||
workspaceKey(session.directory) === workspaceKey(directory) && !session.parentID && !session.time?.archived
|
||||
|
||||
const roots = (store: SessionStore) =>
|
||||
export const roots = (store: SessionStore) =>
|
||||
(store.session ?? []).filter((session) => isRootVisibleSession(session, store.path.directory))
|
||||
|
||||
export const sortedRootSessions = (store: SessionStore, now: number) => roots(store).sort(sortSessions(now))
|
||||
|
||||
@@ -19,6 +19,12 @@ import { childSessionOnPath, hasProjectPermissions } from "./helpers"
|
||||
|
||||
const OPENCODE_PROJECT_ID = "4b0ea68d7af9a6031a7ffda7ad66e0cb83315750"
|
||||
|
||||
export function getProjectAvatarSource(id?: string, icon?: { color?: string; url?: string; override?: string }) {
|
||||
return id === OPENCODE_PROJECT_ID
|
||||
? "https://opencode.ai/favicon.svg"
|
||||
: (icon?.override ?? (icon?.color ? undefined : icon?.url))
|
||||
}
|
||||
|
||||
export const ProjectIcon = (props: { project: LocalProject; class?: string; notify?: boolean }): JSX.Element => {
|
||||
const globalSync = useGlobalSync()
|
||||
const notification = useNotification()
|
||||
@@ -42,9 +48,7 @@ export const ProjectIcon = (props: { project: LocalProject; class?: string; noti
|
||||
<div class="size-full rounded overflow-clip">
|
||||
<Avatar
|
||||
fallback={name()}
|
||||
src={
|
||||
props.project.id === OPENCODE_PROJECT_ID ? "https://opencode.ai/favicon.svg" : props.project.icon?.override
|
||||
}
|
||||
src={getProjectAvatarSource(props.project.id, props.project.icon)}
|
||||
{...getAvatarColors(props.project.icon?.color)}
|
||||
class="size-full rounded"
|
||||
classList={{ "badge-mask": notify() }}
|
||||
@@ -263,10 +267,10 @@ export const SessionItem = (props: SessionItemProps): JSX.Element => {
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
<Show when={currentChild()}>
|
||||
<Show when={currentChild()} keyed>
|
||||
{(child) => (
|
||||
<div class="w-full">
|
||||
<SessionItem {...props} session={child()} level={(props.level ?? 0) + 1} />
|
||||
<SessionItem {...props} session={child} level={(props.level ?? 0) + 1} />
|
||||
</div>
|
||||
)}
|
||||
</Show>
|
||||
|
||||
@@ -14,10 +14,11 @@ import { Spinner } from "@opencode-ai/ui/spinner"
|
||||
import { Tooltip } from "@opencode-ai/ui/tooltip"
|
||||
import { type Session } from "@opencode-ai/sdk/v2/client"
|
||||
import { type LocalProject } from "@/context/layout"
|
||||
import { useGlobalSync } from "@/context/global-sync"
|
||||
import { loadSessionsQuery, useGlobalSync } from "@/context/global-sync"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { NewSessionItem, SessionItem, SessionSkeleton } from "./sidebar-items"
|
||||
import { sortedRootSessions, workspaceKey } from "./helpers"
|
||||
import { useQuery } from "@tanstack/solid-query"
|
||||
|
||||
type InlineEditorComponent = (props: {
|
||||
id: string
|
||||
@@ -277,7 +278,7 @@ const WorkspaceSessionList = (props: {
|
||||
class="flex w-full text-left justify-start text-14-regular text-text-weak pl-2 pr-10"
|
||||
size="large"
|
||||
onClick={(e: MouseEvent) => {
|
||||
props.loadMore()
|
||||
void props.loadMore()
|
||||
;(e.currentTarget as HTMLButtonElement).blur()
|
||||
}}
|
||||
>
|
||||
@@ -316,12 +317,11 @@ export const SortableWorkspace = (props: {
|
||||
})
|
||||
const open = createMemo(() => props.ctx.workspaceExpanded(props.directory, local()))
|
||||
const boot = createMemo(() => open() || active())
|
||||
const booted = createMemo((prev) => prev || workspaceStore.status === "complete", false)
|
||||
const count = createMemo(() => sessions()?.length ?? 0)
|
||||
const hasMore = createMemo(() => workspaceStore.sessionTotal > count())
|
||||
const query = useQuery(() => ({ ...loadSessionsQuery(props.project.worktree) }))
|
||||
const busy = createMemo(() => props.ctx.isBusy(props.directory))
|
||||
const wasBusy = createMemo((prev) => prev || busy(), false)
|
||||
const loading = createMemo(() => open() && !booted() && count() === 0 && !wasBusy())
|
||||
const loading = () => query.isLoading && count() === 0
|
||||
const touch = createMediaQuery("(hover: none)")
|
||||
const showNew = createMemo(() => !loading() && (touch() || count() === 0 || (active() && !params.id)))
|
||||
const loadMore = async () => {
|
||||
@@ -426,7 +426,7 @@ export const SortableWorkspace = (props: {
|
||||
mobile={props.mobile}
|
||||
ctx={props.ctx}
|
||||
showNew={showNew}
|
||||
loading={loading}
|
||||
loading={() => query.isLoading && count() === 0}
|
||||
sessions={sessions}
|
||||
hasMore={hasMore}
|
||||
loadMore={loadMore}
|
||||
@@ -452,10 +452,10 @@ export const LocalWorkspace = (props: {
|
||||
})
|
||||
const slug = createMemo(() => base64Encode(props.project.worktree))
|
||||
const sessions = createMemo(() => sortedRootSessions(workspace().store, props.sortNow()))
|
||||
const booted = createMemo((prev) => prev || workspace().store.status === "complete", false)
|
||||
const count = createMemo(() => sessions()?.length ?? 0)
|
||||
const loading = createMemo(() => !booted() && count() === 0)
|
||||
const query = useQuery(() => ({ ...loadSessionsQuery(props.project.worktree) }))
|
||||
const hasMore = createMemo(() => workspace().store.sessionTotal > count())
|
||||
const loading = () => query.isLoading && count() === 0
|
||||
const loadMore = async () => {
|
||||
workspace().setStore("limit", (limit) => (limit ?? 0) + 5)
|
||||
await globalSync.project.loadSessions(props.project.worktree)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Project, UserMessage, VcsFileDiff } from "@opencode-ai/sdk/v2"
|
||||
import type { Project, UserMessage } from "@opencode-ai/sdk/v2"
|
||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||
import { useMutation } from "@tanstack/solid-query"
|
||||
import { createQuery, skipToken, useMutation, useQueryClient } from "@tanstack/solid-query"
|
||||
import {
|
||||
batch,
|
||||
onCleanup,
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
on,
|
||||
onMount,
|
||||
untrack,
|
||||
createResource,
|
||||
} from "solid-js"
|
||||
import { makeEventListener } from "@solid-primitives/event-listener"
|
||||
import { createMediaQuery } from "@solid-primitives/media"
|
||||
@@ -323,6 +324,7 @@ export default function Page() {
|
||||
const local = useLocal()
|
||||
const file = useFile()
|
||||
const sync = useSync()
|
||||
const queryClient = useQueryClient()
|
||||
const dialog = useDialog()
|
||||
const language = useLanguage()
|
||||
const sdk = useSDK()
|
||||
@@ -432,8 +434,6 @@ export default function Page() {
|
||||
const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined))
|
||||
const isChildSession = createMemo(() => !!info()?.parentID)
|
||||
const diffs = createMemo(() => (params.id ? list(sync.data.session_diff[params.id]) : []))
|
||||
const sessionCount = createMemo(() => Math.max(info()?.summary?.files ?? 0, diffs().length))
|
||||
const hasSessionReview = createMemo(() => sessionCount() > 0)
|
||||
const canReview = createMemo(() => !!sync.project)
|
||||
const reviewTab = createMemo(() => isDesktop())
|
||||
const tabState = createSessionTabs({
|
||||
@@ -443,8 +443,6 @@ export default function Page() {
|
||||
review: reviewTab,
|
||||
hasReview: canReview,
|
||||
})
|
||||
const contextOpen = tabState.contextOpen
|
||||
const openedTabs = tabState.openedTabs
|
||||
const activeTab = tabState.activeTab
|
||||
const activeFileTab = tabState.activeFileTab
|
||||
const revertMessageID = createMemo(() => info()?.revert?.messageID)
|
||||
@@ -487,7 +485,7 @@ export default function Page() {
|
||||
if (!tab) return
|
||||
|
||||
const path = file.pathFromTab(tab)
|
||||
if (path) file.load(path)
|
||||
if (path) void file.load(path)
|
||||
})
|
||||
|
||||
createEffect(
|
||||
@@ -521,26 +519,6 @@ export default function Page() {
|
||||
deferRender: false,
|
||||
})
|
||||
|
||||
const [vcs, setVcs] = createStore<{
|
||||
diff: {
|
||||
git: VcsFileDiff[]
|
||||
branch: VcsFileDiff[]
|
||||
}
|
||||
ready: {
|
||||
git: boolean
|
||||
branch: boolean
|
||||
}
|
||||
}>({
|
||||
diff: {
|
||||
git: [] as VcsFileDiff[],
|
||||
branch: [] as VcsFileDiff[],
|
||||
},
|
||||
ready: {
|
||||
git: false,
|
||||
branch: false,
|
||||
},
|
||||
})
|
||||
|
||||
const [followup, setFollowup] = persisted(
|
||||
Persist.workspace(sdk.directory, "followup", ["followup.v1"]),
|
||||
createStore<{
|
||||
@@ -574,68 +552,6 @@ export default function Page() {
|
||||
let todoTimer: number | undefined
|
||||
let diffFrame: number | undefined
|
||||
let diffTimer: number | undefined
|
||||
const vcsTask = new Map<VcsMode, Promise<void>>()
|
||||
const vcsRun = new Map<VcsMode, number>()
|
||||
|
||||
const bumpVcs = (mode: VcsMode) => {
|
||||
const next = (vcsRun.get(mode) ?? 0) + 1
|
||||
vcsRun.set(mode, next)
|
||||
return next
|
||||
}
|
||||
|
||||
const resetVcs = (mode?: VcsMode) => {
|
||||
const list = mode ? [mode] : (["git", "branch"] as const)
|
||||
list.forEach((item) => {
|
||||
bumpVcs(item)
|
||||
vcsTask.delete(item)
|
||||
setVcs("diff", item, [])
|
||||
setVcs("ready", item, false)
|
||||
})
|
||||
}
|
||||
|
||||
const loadVcs = (mode: VcsMode, force = false) => {
|
||||
if (sync.project?.vcs !== "git") return Promise.resolve()
|
||||
if (!force && vcs.ready[mode]) return Promise.resolve()
|
||||
|
||||
if (force) {
|
||||
if (vcsTask.has(mode)) bumpVcs(mode)
|
||||
vcsTask.delete(mode)
|
||||
setVcs("ready", mode, false)
|
||||
}
|
||||
|
||||
const current = vcsTask.get(mode)
|
||||
if (current) return current
|
||||
|
||||
const run = bumpVcs(mode)
|
||||
|
||||
const task = sdk.client.vcs
|
||||
.diff({ mode })
|
||||
.then((result) => {
|
||||
if (vcsRun.get(mode) !== run) return
|
||||
setVcs("diff", mode, list(result.data))
|
||||
setVcs("ready", mode, true)
|
||||
})
|
||||
.catch((error) => {
|
||||
if (vcsRun.get(mode) !== run) return
|
||||
console.debug("[session-review] failed to load vcs diff", { mode, error })
|
||||
setVcs("diff", mode, [])
|
||||
setVcs("ready", mode, true)
|
||||
})
|
||||
.finally(() => {
|
||||
if (vcsTask.get(mode) === task) vcsTask.delete(mode)
|
||||
})
|
||||
|
||||
vcsTask.set(mode, task)
|
||||
return task
|
||||
}
|
||||
|
||||
const refreshVcs = () => {
|
||||
resetVcs()
|
||||
const mode = untrack(vcsMode)
|
||||
if (!mode) return
|
||||
if (!untrack(wantsReview)) return
|
||||
void loadVcs(mode, true)
|
||||
}
|
||||
|
||||
createComputed((prev) => {
|
||||
const open = desktopReviewOpen()
|
||||
@@ -666,21 +582,52 @@ export default function Page() {
|
||||
list.push("turn")
|
||||
return list
|
||||
})
|
||||
const mobileChanges = createMemo(() => !isDesktop() && store.mobileTab === "changes")
|
||||
const wantsReview = createMemo(() =>
|
||||
isDesktop()
|
||||
? desktopFileTreeOpen() || (desktopReviewOpen() && activeTab() === "review")
|
||||
: store.mobileTab === "changes",
|
||||
)
|
||||
const vcsMode = createMemo<VcsMode | undefined>(() => {
|
||||
if (store.changes === "git" || store.changes === "branch") return store.changes
|
||||
})
|
||||
const reviewDiffs = createMemo(() => {
|
||||
if (store.changes === "git") return list(vcs.diff.git)
|
||||
if (store.changes === "branch") return list(vcs.diff.branch)
|
||||
const vcsKey = createMemo(
|
||||
() => ["session-vcs", sdk.directory, sync.data.vcs?.branch ?? "", sync.data.vcs?.default_branch ?? ""] as const,
|
||||
)
|
||||
const vcsQuery = createQuery(() => {
|
||||
const mode = vcsMode()
|
||||
const enabled = wantsReview() && sync.project?.vcs === "git"
|
||||
|
||||
return {
|
||||
queryKey: [...vcsKey(), mode] as const,
|
||||
enabled,
|
||||
staleTime: Number.POSITIVE_INFINITY,
|
||||
gcTime: 60 * 1000,
|
||||
queryFn: mode
|
||||
? () =>
|
||||
sdk.client.vcs
|
||||
.diff({ mode })
|
||||
.then((result) => list(result.data))
|
||||
.catch((error) => {
|
||||
console.debug("[session-review] failed to load vcs diff", { mode, error })
|
||||
return []
|
||||
})
|
||||
: skipToken,
|
||||
}
|
||||
})
|
||||
const refreshVcs = () => void queryClient.invalidateQueries({ queryKey: vcsKey() })
|
||||
const reviewDiffs = () => {
|
||||
if (store.changes === "git" || store.changes === "branch")
|
||||
// avoids suspense
|
||||
return vcsQuery.isFetched ? (vcsQuery.data ?? []) : []
|
||||
return turnDiffs()
|
||||
})
|
||||
const reviewCount = createMemo(() => reviewDiffs().length)
|
||||
const hasReview = createMemo(() => reviewCount() > 0)
|
||||
const reviewReady = createMemo(() => {
|
||||
if (store.changes === "git") return vcs.ready.git
|
||||
if (store.changes === "branch") return vcs.ready.branch
|
||||
}
|
||||
const reviewCount = () => reviewDiffs().length
|
||||
const hasReview = () => reviewCount() > 0
|
||||
const reviewReady = () => {
|
||||
if (store.changes === "git" || store.changes === "branch") return !vcsQuery.isPending
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
const newSessionWorktree = createMemo(() => {
|
||||
if (store.newSessionWorktree === "create") return "create"
|
||||
@@ -808,8 +755,9 @@ export default function Page() {
|
||||
|
||||
const hasScrollGesture = () => Date.now() - ui.scrollGesture < scrollGestureWindowMs
|
||||
|
||||
createEffect(
|
||||
on([() => sdk.directory, () => params.id] as const, ([, id]) => {
|
||||
const [sessionSync] = createResource(
|
||||
() => [sdk.directory, params.id] as const,
|
||||
([directory, id]) => {
|
||||
if (refreshFrame !== undefined) cancelAnimationFrame(refreshFrame)
|
||||
if (refreshTimer !== undefined) window.clearTimeout(refreshTimer)
|
||||
refreshFrame = undefined
|
||||
@@ -820,13 +768,10 @@ export default function Page() {
|
||||
const stale = !cached
|
||||
? false
|
||||
: (() => {
|
||||
const info = getSessionPrefetch(sdk.directory, id)
|
||||
const info = getSessionPrefetch(directory, id)
|
||||
if (!info) return true
|
||||
return Date.now() - info.at > SESSION_PREFETCH_TTL
|
||||
})()
|
||||
untrack(() => {
|
||||
void sync.session.sync(id)
|
||||
})
|
||||
|
||||
refreshFrame = requestAnimationFrame(() => {
|
||||
refreshFrame = undefined
|
||||
@@ -838,7 +783,9 @@ export default function Page() {
|
||||
})
|
||||
}, 0)
|
||||
})
|
||||
}),
|
||||
|
||||
return sync.session.sync(id)
|
||||
},
|
||||
)
|
||||
|
||||
createEffect(
|
||||
@@ -900,27 +847,6 @@ export default function Page() {
|
||||
),
|
||||
)
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
() => sdk.directory,
|
||||
() => {
|
||||
resetVcs()
|
||||
},
|
||||
{ defer: true },
|
||||
),
|
||||
)
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
() => [sync.data.vcs?.branch, sync.data.vcs?.default_branch] as const,
|
||||
(next, prev) => {
|
||||
if (prev === undefined || same(next, prev)) return
|
||||
refreshVcs()
|
||||
},
|
||||
{ defer: true },
|
||||
),
|
||||
)
|
||||
|
||||
const stopVcs = sdk.event.listen((evt) => {
|
||||
if (evt.details.type !== "file.watcher.updated") return
|
||||
const props =
|
||||
@@ -1054,13 +980,6 @@ export default function Page() {
|
||||
}
|
||||
}
|
||||
|
||||
const mobileChanges = createMemo(() => !isDesktop() && store.mobileTab === "changes")
|
||||
const wantsReview = createMemo(() =>
|
||||
isDesktop()
|
||||
? desktopFileTreeOpen() || (desktopReviewOpen() && activeTab() === "review")
|
||||
: store.mobileTab === "changes",
|
||||
)
|
||||
|
||||
createEffect(() => {
|
||||
const list = changesOptions()
|
||||
if (list.includes(store.changes)) return
|
||||
@@ -1069,22 +988,12 @@ export default function Page() {
|
||||
setStore("changes", next)
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
const mode = vcsMode()
|
||||
if (!mode) return
|
||||
if (!wantsReview()) return
|
||||
void loadVcs(mode)
|
||||
})
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
() => sync.data.session_status[params.id ?? ""]?.type,
|
||||
(next, prev) => {
|
||||
const mode = vcsMode()
|
||||
if (!mode) return
|
||||
if (!wantsReview()) return
|
||||
if (next !== "idle" || prev === undefined || prev === "idle") return
|
||||
void loadVcs(mode, true)
|
||||
refreshVcs()
|
||||
},
|
||||
{ defer: true },
|
||||
),
|
||||
@@ -1885,6 +1794,7 @@ export default function Page() {
|
||||
|
||||
return (
|
||||
<div class="relative bg-background-base size-full overflow-hidden flex flex-col">
|
||||
{sessionSync() ?? ""}
|
||||
<SessionHeader />
|
||||
<div class="flex-1 min-h-0 flex flex-col md:flex-row">
|
||||
<Show when={!isDesktop() && !!params.id}>
|
||||
|
||||
@@ -378,12 +378,6 @@ export function FileTabContent(props: { tab: string }) {
|
||||
requestAnimationFrame(() => comments.clearFocus())
|
||||
})
|
||||
|
||||
const cancelCommenting = () => {
|
||||
const p = path()
|
||||
if (p) file.setSelectedLines(p, null)
|
||||
setNote("commenting", null)
|
||||
}
|
||||
|
||||
let prev = {
|
||||
loaded: false,
|
||||
ready: false,
|
||||
|
||||
@@ -117,7 +117,7 @@ export const createOpenReviewFile = (input: {
|
||||
input.openTab(tab)
|
||||
input.setActive(tab)
|
||||
}
|
||||
if (maybePromise instanceof Promise) maybePromise.then(open)
|
||||
if (maybePromise instanceof Promise) void maybePromise.then(open)
|
||||
else open()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ export function MessageTimeline(props: {
|
||||
if (!id) return idle
|
||||
return sync.data.session_status[id] ?? idle
|
||||
})
|
||||
const working = createMemo(() => !!pending() || sessionStatus().type !== "idle")
|
||||
const working = createMemo(() => sessionStatus().type !== "idle")
|
||||
const tint = createMemo(() => messageAgentColor(sessionMessages(), sync.data.agent))
|
||||
|
||||
const [timeoutDone, setTimeoutDone] = createSignal(true)
|
||||
@@ -721,7 +721,7 @@ export function MessageTimeline(props: {
|
||||
"md:max-w-200 md:mx-auto 2xl:max-w-[1000px]": props.centered,
|
||||
}}
|
||||
>
|
||||
<Show when={workingStatus() !== "hidden"}>
|
||||
<Show when={workingStatus() !== "hidden" && settings.general.showSessionProgressBar()}>
|
||||
<div
|
||||
data-component="session-progress"
|
||||
data-state={workingStatus()}
|
||||
@@ -812,7 +812,7 @@ export function MessageTimeline(props: {
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
<Show when={sessionID()}>
|
||||
<Show when={sessionID()} keyed>
|
||||
{(id) => (
|
||||
<div class="shrink-0 flex items-center gap-3">
|
||||
<SessionContextUsage placement="bottom" />
|
||||
@@ -878,12 +878,12 @@ export function MessageTimeline(props: {
|
||||
</DropdownMenu.ItemLabel>
|
||||
</DropdownMenu.Item>
|
||||
</Show>
|
||||
<DropdownMenu.Item onSelect={() => void archiveSession(id())}>
|
||||
<DropdownMenu.Item onSelect={() => void archiveSession(id)}>
|
||||
<DropdownMenu.ItemLabel>{language.t("common.archive")}</DropdownMenu.ItemLabel>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item
|
||||
onSelect={() => dialog.show(() => <DialogDeleteSession sessionID={id()} />)}
|
||||
onSelect={() => dialog.show(() => <DialogDeleteSession sessionID={id} />)}
|
||||
>
|
||||
<DropdownMenu.ItemLabel>{language.t("common.delete")}</DropdownMenu.ItemLabel>
|
||||
</DropdownMenu.Item>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createEffect, createSignal, onCleanup, type JSX } from "solid-js"
|
||||
import { createEffect, onCleanup, type JSX } from "solid-js"
|
||||
import { makeEventListener } from "@solid-primitives/event-listener"
|
||||
import type { SnapshotFileDiff, VcsFileDiff } from "@opencode-ai/sdk/v2"
|
||||
import { SessionReview } from "@opencode-ai/ui/session-review"
|
||||
|
||||
@@ -19,6 +19,9 @@ import { useCommand } from "@/context/command"
|
||||
import { useFile, type SelectedLineRange } from "@/context/file"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { useLayout } from "@/context/layout"
|
||||
import { usePlatform } from "@/context/platform"
|
||||
import { useSettings } from "@/context/settings"
|
||||
import { useSync } from "@/context/sync"
|
||||
import { createFileTabListSync } from "@/pages/session/file-tab-scroll"
|
||||
import { FileTabContent } from "@/pages/session/file-tabs"
|
||||
import { createOpenSessionFileTab, createSessionTabs, getTabReorderIndex, type Sizing } from "@/pages/session/helpers"
|
||||
@@ -39,6 +42,9 @@ export function SessionSidePanel(props: {
|
||||
size: Sizing
|
||||
}) {
|
||||
const layout = useLayout()
|
||||
const platform = usePlatform()
|
||||
const settings = useSettings()
|
||||
const sync = useSync()
|
||||
const file = useFile()
|
||||
const language = useLanguage()
|
||||
const command = useCommand()
|
||||
@@ -46,9 +52,15 @@ export function SessionSidePanel(props: {
|
||||
const { sessionKey, tabs, view } = useSessionLayout()
|
||||
|
||||
const isDesktop = createMediaQuery("(min-width: 768px)")
|
||||
const shown = createMemo(
|
||||
() =>
|
||||
platform.platform !== "desktop" ||
|
||||
import.meta.env.VITE_OPENCODE_CHANNEL !== "beta" ||
|
||||
settings.general.showFileTree(),
|
||||
)
|
||||
|
||||
const reviewOpen = createMemo(() => isDesktop() && view().reviewPanel.opened())
|
||||
const fileOpen = createMemo(() => isDesktop() && layout.fileTree.opened())
|
||||
const fileOpen = createMemo(() => isDesktop() && shown() && layout.fileTree.opened())
|
||||
const open = createMemo(() => reviewOpen() || fileOpen())
|
||||
const reviewTab = createMemo(() => isDesktop())
|
||||
const panelWidth = createMemo(() => {
|
||||
@@ -341,98 +353,99 @@ export function SessionSidePanel(props: {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="file-tree-panel"
|
||||
aria-hidden={!fileOpen()}
|
||||
inert={!fileOpen()}
|
||||
class="relative min-w-0 h-full shrink-0 overflow-hidden"
|
||||
classList={{
|
||||
"pointer-events-none": !fileOpen(),
|
||||
"transition-[width] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-[width] motion-reduce:transition-none":
|
||||
!props.size.active(),
|
||||
}}
|
||||
style={{ width: treeWidth() }}
|
||||
>
|
||||
<Show when={shown()}>
|
||||
<div
|
||||
class="h-full flex flex-col overflow-hidden group/filetree"
|
||||
classList={{ "border-l border-border-weaker-base": reviewOpen() }}
|
||||
id="file-tree-panel"
|
||||
aria-hidden={!fileOpen()}
|
||||
inert={!fileOpen()}
|
||||
class="relative min-w-0 h-full shrink-0 overflow-hidden"
|
||||
classList={{
|
||||
"pointer-events-none": !fileOpen(),
|
||||
"transition-[width] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-[width] motion-reduce:transition-none":
|
||||
!props.size.active(),
|
||||
}}
|
||||
style={{ width: treeWidth() }}
|
||||
>
|
||||
<Tabs
|
||||
variant="pill"
|
||||
value={fileTreeTab()}
|
||||
onChange={setFileTreeTabValue}
|
||||
class="h-full"
|
||||
data-scope="filetree"
|
||||
<div
|
||||
class="h-full flex flex-col overflow-hidden group/filetree"
|
||||
classList={{ "border-l border-border-weaker-base": reviewOpen() }}
|
||||
>
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="changes" class="flex-1" classes={{ button: "w-full" }}>
|
||||
{props.reviewCount()}{" "}
|
||||
{language.t(
|
||||
props.reviewCount() === 1 ? "session.review.change.one" : "session.review.change.other",
|
||||
)}
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="all" class="flex-1" classes={{ button: "w-full" }}>
|
||||
{language.t("session.files.all")}
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<Tabs.Content value="changes" class="bg-background-stronger px-3 py-0">
|
||||
<Switch>
|
||||
<Match when={props.hasReview() || !props.diffsReady()}>
|
||||
<Show
|
||||
when={props.diffsReady()}
|
||||
fallback={
|
||||
<div class="px-2 py-2 text-12-regular text-text-weak">
|
||||
{language.t("common.loading")}
|
||||
{language.t("common.loading.ellipsis")}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Tabs
|
||||
variant="pill"
|
||||
value={fileTreeTab()}
|
||||
onChange={setFileTreeTabValue}
|
||||
class="h-full"
|
||||
data-scope="filetree"
|
||||
>
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="changes" class="flex-1" classes={{ button: "w-full" }}>
|
||||
{props.reviewCount()}{" "}
|
||||
{language.t(
|
||||
props.reviewCount() === 1 ? "session.review.change.one" : "session.review.change.other",
|
||||
)}
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="all" class="flex-1" classes={{ button: "w-full" }}>
|
||||
{language.t("session.files.all")}
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<Tabs.Content value="changes" class="bg-background-stronger px-3 py-0">
|
||||
<Switch>
|
||||
<Match when={props.hasReview() || !props.diffsReady()}>
|
||||
<Show
|
||||
when={props.diffsReady()}
|
||||
fallback={
|
||||
<div class="px-2 py-2 text-12-regular text-text-weak">
|
||||
{language.t("common.loading")}
|
||||
{language.t("common.loading.ellipsis")}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<FileTree
|
||||
path=""
|
||||
class="pt-3"
|
||||
allowed={diffFiles()}
|
||||
kinds={kinds()}
|
||||
draggable={false}
|
||||
active={props.activeDiff}
|
||||
onFileClick={(node) => props.focusReviewDiff(node.path)}
|
||||
/>
|
||||
</Show>
|
||||
</Match>
|
||||
</Switch>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="all" class="bg-background-stronger px-3 py-0">
|
||||
<Switch>
|
||||
<Match when={nofiles()}>{empty(language.t("session.files.empty"))}</Match>
|
||||
<Match when={true}>
|
||||
<FileTree
|
||||
path=""
|
||||
class="pt-3"
|
||||
allowed={diffFiles()}
|
||||
modified={diffFiles()}
|
||||
kinds={kinds()}
|
||||
draggable={false}
|
||||
active={props.activeDiff}
|
||||
onFileClick={(node) => props.focusReviewDiff(node.path)}
|
||||
onFileClick={(node) => openTab(file.tab(node.path))}
|
||||
/>
|
||||
</Show>
|
||||
</Match>
|
||||
<Match when={true}>{empty(props.empty())}</Match>
|
||||
</Switch>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="all" class="bg-background-stronger px-3 py-0">
|
||||
<Switch>
|
||||
<Match when={nofiles()}>{empty(language.t("session.files.empty"))}</Match>
|
||||
<Match when={true}>
|
||||
<FileTree
|
||||
path=""
|
||||
class="pt-3"
|
||||
modified={diffFiles()}
|
||||
kinds={kinds()}
|
||||
onFileClick={(node) => openTab(file.tab(node.path))}
|
||||
/>
|
||||
</Match>
|
||||
</Switch>
|
||||
</Tabs.Content>
|
||||
</Tabs>
|
||||
</div>
|
||||
<Show when={fileOpen()}>
|
||||
<div onPointerDown={() => props.size.start()}>
|
||||
<ResizeHandle
|
||||
direction="horizontal"
|
||||
edge="start"
|
||||
size={layout.fileTree.width()}
|
||||
min={200}
|
||||
max={480}
|
||||
onResize={(width) => {
|
||||
props.size.touch()
|
||||
layout.fileTree.resize(width)
|
||||
}}
|
||||
/>
|
||||
</Match>
|
||||
</Switch>
|
||||
</Tabs.Content>
|
||||
</Tabs>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
<Show when={fileOpen()}>
|
||||
<div onPointerDown={() => props.size.start()}>
|
||||
<ResizeHandle
|
||||
direction="horizontal"
|
||||
edge="start"
|
||||
size={layout.fileTree.width()}
|
||||
min={200}
|
||||
max={480}
|
||||
onResize={(width) => {
|
||||
props.size.touch()
|
||||
layout.fileTree.resize(width)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</aside>
|
||||
</Show>
|
||||
|
||||
@@ -7,8 +7,10 @@ import { useLanguage } from "@/context/language"
|
||||
import { useLayout } from "@/context/layout"
|
||||
import { useLocal } from "@/context/local"
|
||||
import { usePermission } from "@/context/permission"
|
||||
import { usePlatform } from "@/context/platform"
|
||||
import { usePrompt } from "@/context/prompt"
|
||||
import { useSDK } from "@/context/sdk"
|
||||
import { useSettings } from "@/context/settings"
|
||||
import { useSync } from "@/context/sync"
|
||||
import { useTerminal } from "@/context/terminal"
|
||||
import { showToast } from "@opencode-ai/ui/toast"
|
||||
@@ -39,8 +41,10 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
|
||||
const language = useLanguage()
|
||||
const local = useLocal()
|
||||
const permission = usePermission()
|
||||
const platform = usePlatform()
|
||||
const prompt = usePrompt()
|
||||
const sdk = useSDK()
|
||||
const settings = useSettings()
|
||||
const sync = useSync()
|
||||
const terminal = useTerminal()
|
||||
const layout = useLayout()
|
||||
@@ -66,6 +70,10 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
|
||||
})
|
||||
const activeFileTab = tabState.activeFileTab
|
||||
const closableTab = tabState.closableTab
|
||||
const shown = () =>
|
||||
platform.platform !== "desktop" ||
|
||||
import.meta.env.VITE_OPENCODE_CHANNEL !== "beta" ||
|
||||
settings.general.showFileTree()
|
||||
|
||||
const idle = { type: "idle" as const }
|
||||
const status = () => sync.data.session_status[params.id ?? ""] ?? idle
|
||||
@@ -457,12 +465,16 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
|
||||
keybind: "mod+shift+r",
|
||||
onSelect: () => view().reviewPanel.toggle(),
|
||||
}),
|
||||
viewCommand({
|
||||
id: "fileTree.toggle",
|
||||
title: language.t("command.fileTree.toggle"),
|
||||
keybind: "mod+\\",
|
||||
onSelect: () => layout.fileTree.toggle(),
|
||||
}),
|
||||
...(shown()
|
||||
? [
|
||||
viewCommand({
|
||||
id: "fileTree.toggle",
|
||||
title: language.t("command.fileTree.toggle"),
|
||||
keybind: "mod+\\",
|
||||
onSelect: () => layout.fileTree.toggle(),
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
viewCommand({
|
||||
id: "input.focus",
|
||||
title: language.t("command.input.focus"),
|
||||
|
||||
@@ -469,7 +469,7 @@ export function persisted<T>(
|
||||
state,
|
||||
setState,
|
||||
init,
|
||||
Object.assign(() => ready() === true, {
|
||||
Object.assign(() => (ready.loading ? false : ready.latest === true), {
|
||||
promise: init instanceof Promise ? init : undefined,
|
||||
}),
|
||||
]
|
||||
|
||||
@@ -46,7 +46,9 @@ describe("runtime adapters", () => {
|
||||
})
|
||||
|
||||
test("resolves speech recognition constructor with webkit precedence", () => {
|
||||
// oxlint-disable-next-line no-extraneous-class
|
||||
class SpeechCtor {}
|
||||
// oxlint-disable-next-line no-extraneous-class
|
||||
class WebkitCtor {}
|
||||
const ctor = getSpeechRecognitionCtor({
|
||||
SpeechRecognition: SpeechCtor,
|
||||
|
||||
@@ -16,7 +16,10 @@ export function createSdkForServer({
|
||||
|
||||
return createOpencodeClient({
|
||||
...config,
|
||||
headers: { ...config.headers, ...auth },
|
||||
headers: {
|
||||
...(config.headers instanceof Headers ? Object.fromEntries(config.headers.entries()) : config.headers),
|
||||
...auth,
|
||||
},
|
||||
baseUrl: server.url,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.4.6",
|
||||
"version": "1.14.24",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -8,7 +8,6 @@ import { LOCALES, route } from "../src/lib/language.js"
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const BASE_URL = config.baseUrl
|
||||
const PUBLIC_DIR = join(__dirname, "../public")
|
||||
const ROUTES_DIR = join(__dirname, "../src/routes")
|
||||
const DOCS_DIR = join(__dirname, "../../../web/src/content/docs")
|
||||
|
||||
interface SitemapEntry {
|
||||
@@ -106,4 +105,4 @@ async function main() {
|
||||
console.log(`✓ Sitemap generated at ${outputPath}`)
|
||||
}
|
||||
|
||||
main()
|
||||
void main()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { action, useSubmission } from "@solidjs/router"
|
||||
import dock from "../asset/lander/dock.png"
|
||||
import { Resource } from "@opencode-ai/console-resource"
|
||||
import { Show } from "solid-js"
|
||||
import { useI18n } from "~/context/i18n"
|
||||
|
||||
@@ -47,7 +47,7 @@ export function Header(props: { zen?: boolean; go?: boolean; hideGetStarted?: bo
|
||||
notation: "compact",
|
||||
compactDisplay: "short",
|
||||
maximumFractionDigits: 0,
|
||||
}).format(githubData()?.stars!)
|
||||
}).format(githubData()?.stars)
|
||||
: config.github.starsFormatted.compact,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { JSX } from "solid-js"
|
||||
|
||||
export function IconZen(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
|
||||
export function IconZen(_props: JSX.SvgSVGAttributes<SVGSVGElement>) {
|
||||
return (
|
||||
<svg width="84" height="30" viewBox="0 0 84 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M24 24H6V18H18V12H24V24ZM6 18H0V12H6V18Z" fill="currentColor" fill-opacity="0.2" />
|
||||
@@ -13,7 +13,7 @@ export function IconZen(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
|
||||
)
|
||||
}
|
||||
|
||||
export function IconGo(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
|
||||
export function IconGo(_props: JSX.SvgSVGAttributes<SVGSVGElement>) {
|
||||
return (
|
||||
<svg width="54" height="30" viewBox="0 0 54 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M24 30H0V0H24V6H6V24H18V18H12V12H24V30Z" fill="currentColor" />
|
||||
|
||||
@@ -766,7 +766,7 @@ export default function Spotlight(props: SpotlightProps) {
|
||||
}
|
||||
}
|
||||
|
||||
initializeWebGPU()
|
||||
void initializeWebGPU()
|
||||
|
||||
onCleanup(() => {
|
||||
if (cleanupFunctionRef) {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export {}
|
||||
|
||||
@@ -11,7 +11,7 @@ export const dict = {
|
||||
"nav.enterprise": "المؤسسات",
|
||||
"nav.zen": "Zen",
|
||||
"nav.login": "تسجيل الدخول",
|
||||
"nav.free": "مجانا",
|
||||
"nav.free": "تحميل",
|
||||
"nav.home": "الرئيسية",
|
||||
"nav.openMenu": "فتح القائمة",
|
||||
"nav.getStartedFree": "ابدأ مجانا",
|
||||
@@ -249,7 +249,7 @@ export const dict = {
|
||||
|
||||
"go.title": "OpenCode Go | نماذج برمجة منخفضة التكلفة للجميع",
|
||||
"go.meta.description":
|
||||
"يبدأ Go من $5 للشهر الأول، ثم $10/شهر، مع حدود طلب سخية لمدة 5 ساعات لـ GLM-5.1 وGLM-5 و Kimi K2.5 وMiMo-V2-Pro وMiMo-V2-Omni و Qwen3.5 Plus و Qwen3.6 Plus و MiniMax M2.5 وMiniMax M2.7.",
|
||||
"يبدأ Go من $5 للشهر الأول، ثم $10/شهر، مع حدود طلب سخية لمدة 5 ساعات لـ GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 وDeepSeek V4 Pro وDeepSeek V4 Flash.",
|
||||
"go.hero.title": "نماذج برمجة منخفضة التكلفة للجميع",
|
||||
"go.hero.body":
|
||||
"يجلب Go البرمجة الوكيلة للمبرمجين حول العالم. يوفر حدودًا سخية ووصولًا موثوقًا إلى أقوى النماذج مفتوحة المصدر، حتى تتمكن من البناء باستخدام وكلاء أقوياء دون القلق بشأن التكلفة أو التوفر.",
|
||||
@@ -261,6 +261,8 @@ export const dict = {
|
||||
"go.cta.promo": "$5 للشهر الأول",
|
||||
"go.pricing.body":
|
||||
"استخدمه مع أي وكيل. $5 للشهر الأول، ثم $10/شهر. قم بزيادة الرصيد إذا لزم الأمر. الإلغاء في أي وقت.",
|
||||
"go.banner.badge": "3x",
|
||||
"go.banner.text": "Kimi K2.6: حد الاستخدام 3 أضعاف حتى 27 أبريل",
|
||||
"go.graph.free": "مجاني",
|
||||
"go.graph.freePill": "Big Pickle ونماذج مجانية",
|
||||
"go.graph.go": "Go",
|
||||
@@ -298,7 +300,7 @@ export const dict = {
|
||||
"go.problem.item2": "حدود سخية ووصول موثوق",
|
||||
"go.problem.item3": "مصمم لأكبر عدد ممكن من المبرمجين",
|
||||
"go.problem.item4":
|
||||
"يتضمن GLM-5.1 وGLM-5 وKimi K2.5 وMiMo-V2-Pro وMiMo-V2-Omni وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7",
|
||||
"يتضمن GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 وDeepSeek V4 Pro وDeepSeek V4 Flash",
|
||||
"go.how.title": "كيف يعمل Go",
|
||||
"go.how.body": "يبدأ Go من $5 للشهر الأول، ثم $10/شهر. يمكنك استخدامه مع OpenCode أو أي وكيل.",
|
||||
"go.how.step1.title": "أنشئ حسابًا",
|
||||
@@ -322,7 +324,7 @@ export const dict = {
|
||||
"go.faq.a2": "يتضمن Go النماذج المدرجة أدناه، مع حدود سخية وإتاحة موثوقة.",
|
||||
"go.faq.q3": "هل Go هو نفسه Zen؟",
|
||||
"go.faq.a3":
|
||||
"لا. Zen هو الدفع حسب الاستخدام، بينما يبدأ Go من $5 للشهر الأول، ثم $10/شهر، مع حدود سخية ووصول موثوق إلى نماذج المصدر المفتوح GLM-5.1 وGLM-5 و Kimi K2.5 وMiMo-V2-Pro وMiMo-V2-Omni و Qwen3.5 Plus و Qwen3.6 Plus و MiniMax M2.5 وMiniMax M2.7.",
|
||||
"لا. Zen هو الدفع حسب الاستخدام، بينما يبدأ Go من $5 للشهر الأول، ثم $10/شهر، مع حدود سخية ووصول موثوق إلى نماذج المصدر المفتوح GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 وDeepSeek V4 Pro وDeepSeek V4 Flash.",
|
||||
"go.faq.q4": "كم تكلفة Go؟",
|
||||
"go.faq.a4.p1.beforePricing": "تكلفة Go",
|
||||
"go.faq.a4.p1.pricingLink": "$5 للشهر الأول",
|
||||
@@ -345,7 +347,7 @@ export const dict = {
|
||||
|
||||
"go.faq.q9": "ما الفرق بين النماذج المجانية وGo؟",
|
||||
"go.faq.a9":
|
||||
"تشمل النماذج المجانية Big Pickle بالإضافة إلى النماذج الترويجية المتاحة في ذلك الوقت، مع حصة 200 طلب/يوم. يتضمن Go نماذج GLM-5.1 وGLM-5 وKimi K2.5 وMiMo-V2-Pro وMiMo-V2-Omni وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 مع حصص طلبات أعلى مطبقة عبر نوافذ متجددة (5 ساعات، أسبوعيًا، وشهريًا)، تعادل تقريبًا 12 دولارًا كل 5 ساعات، و30 دولارًا في الأسبوع، و60 دولارًا في الشهر (تختلف أعداد الطلبات الفعلية حسب النموذج والاستخدام).",
|
||||
"تشمل النماذج المجانية Big Pickle بالإضافة إلى النماذج الترويجية المتاحة في ذلك الوقت، مع حصة 200 طلب/يوم. يتضمن Go نماذج GLM-5.1 وGLM-5 وKimi K2.5 وKimi K2.6 وMiMo-V2-Pro وMiMo-V2-Omni وMiMo-V2.5-Pro وMiMo-V2.5 وQwen3.5 Plus وQwen3.6 Plus وMiniMax M2.5 وMiniMax M2.7 وDeepSeek V4 Pro وDeepSeek V4 Flash مع حصص طلبات أعلى مطبقة عبر نوافذ متجددة (5 ساعات، أسبوعيًا، وشهريًا)، تعادل تقريبًا 12 دولارًا كل 5 ساعات، و30 دولارًا في الأسبوع، و60 دولارًا في الشهر (تختلف أعداد الطلبات الفعلية حسب النموذج والاستخدام).",
|
||||
|
||||
"zen.api.error.rateLimitExceeded": "تم تجاوز حد الطلبات. يرجى المحاولة مرة أخرى لاحقًا.",
|
||||
"zen.api.error.modelNotSupported": "النموذج {{model}} غير مدعوم",
|
||||
@@ -558,6 +560,13 @@ export const dict = {
|
||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "الاستخدام الحالي لـ",
|
||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "هو $",
|
||||
|
||||
"workspace.redeem.title": "استرداد قسيمة",
|
||||
"workspace.redeem.subtitle": "استرد رمز القسيمة للحصول على رصيد أو مزايا.",
|
||||
"workspace.redeem.placeholder": "أدخل رمز القسيمة",
|
||||
"workspace.redeem.redeem": "استرداد",
|
||||
"workspace.redeem.redeeming": "جارٍ الاسترداد...",
|
||||
"workspace.redeem.success": "تم استرداد القسيمة بنجاح.",
|
||||
|
||||
"workspace.reload.title": "إعادة الشحن التلقائي",
|
||||
"workspace.reload.disabled.before": "إعادة الشحن التلقائي",
|
||||
"workspace.reload.disabled.state": "معطّل",
|
||||
|
||||
@@ -11,7 +11,7 @@ export const dict = {
|
||||
"nav.enterprise": "Enterprise",
|
||||
"nav.zen": "Zen",
|
||||
"nav.login": "Entrar",
|
||||
"nav.free": "Grátis",
|
||||
"nav.free": "Download",
|
||||
"nav.home": "Início",
|
||||
"nav.openMenu": "Abrir menu",
|
||||
"nav.getStartedFree": "Começar grátis",
|
||||
@@ -253,7 +253,7 @@ export const dict = {
|
||||
|
||||
"go.title": "OpenCode Go | Modelos de codificação de baixo custo para todos",
|
||||
"go.meta.description":
|
||||
"O Go começa em $5 no primeiro mês, depois $10/mês, com limites generosos de solicitação de 5 horas para GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7.",
|
||||
"O Go começa em $5 no primeiro mês, depois $10/mês, com limites generosos de solicitação de 5 horas para GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash.",
|
||||
"go.hero.title": "Modelos de codificação de baixo custo para todos",
|
||||
"go.hero.body":
|
||||
"O Go traz a codificação com agentes para programadores em todo o mundo. Oferecendo limites generosos e acesso confiável aos modelos de código aberto mais capazes, para que você possa construir com agentes poderosos sem se preocupar com custos ou disponibilidade.",
|
||||
@@ -265,6 +265,8 @@ export const dict = {
|
||||
"go.cta.promo": "$5 no primeiro mês",
|
||||
"go.pricing.body":
|
||||
"Use com qualquer agente. $5 no primeiro mês, depois $10/mês. Recarregue o crédito se necessário. Cancele a qualquer momento.",
|
||||
"go.banner.badge": "3x",
|
||||
"go.banner.text": "Kimi K2.6: limite de uso 3x maior até 27 de abril",
|
||||
"go.graph.free": "Grátis",
|
||||
"go.graph.freePill": "Big Pickle e modelos gratuitos",
|
||||
"go.graph.go": "Go",
|
||||
@@ -303,7 +305,7 @@ export const dict = {
|
||||
"go.problem.item2": "Limites generosos e acesso confiável",
|
||||
"go.problem.item3": "Feito para o maior número possível de programadores",
|
||||
"go.problem.item4":
|
||||
"Inclui GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7",
|
||||
"Inclui GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash",
|
||||
"go.how.title": "Como o Go funciona",
|
||||
"go.how.body":
|
||||
"O Go começa em $5 no primeiro mês, depois $10/mês. Você pode usá-lo com o OpenCode ou qualquer agente.",
|
||||
@@ -329,7 +331,7 @@ export const dict = {
|
||||
"go.faq.a2": "O Go inclui os modelos listados abaixo, com limites generosos e acesso confiável.",
|
||||
"go.faq.q3": "O Go é o mesmo que o Zen?",
|
||||
"go.faq.a3":
|
||||
"Não. Zen é pay-as-you-go, enquanto o Go começa em $5 no primeiro mês, depois $10/mês, com limites generosos e acesso confiável aos modelos open source GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7.",
|
||||
"Não. Zen é pay-as-you-go, enquanto o Go começa em $5 no primeiro mês, depois $10/mês, com limites generosos e acesso confiável aos modelos open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash.",
|
||||
"go.faq.q4": "Quanto custa o Go?",
|
||||
"go.faq.a4.p1.beforePricing": "O Go custa",
|
||||
"go.faq.a4.p1.pricingLink": "$5 no primeiro mês",
|
||||
@@ -353,7 +355,7 @@ export const dict = {
|
||||
|
||||
"go.faq.q9": "Qual a diferença entre os modelos gratuitos e o Go?",
|
||||
"go.faq.a9":
|
||||
"Os modelos gratuitos incluem Big Pickle e modelos promocionais disponíveis no momento, com uma cota de 200 requisições/dia. O Go inclui GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 e MiniMax M2.7 com cotas de requisição mais altas aplicadas em janelas móveis (5 horas, semanal e mensal), aproximadamente equivalentes a $12 por 5 horas, $30 por semana e $60 por mês (as contagens reais de requisições variam de acordo com o modelo e o uso).",
|
||||
"Os modelos gratuitos incluem Big Pickle e modelos promocionais disponíveis no momento, com uma cota de 200 requisições/dia. O Go inclui GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro e DeepSeek V4 Flash com cotas de requisição mais altas aplicadas em janelas móveis (5 horas, semanal e mensal), aproximadamente equivalentes a $12 por 5 horas, $30 por semana e $60 por mês (as contagens reais de requisições variam de acordo com o modelo e o uso).",
|
||||
|
||||
"zen.api.error.rateLimitExceeded": "Limite de taxa excedido. Por favor, tente novamente mais tarde.",
|
||||
"zen.api.error.modelNotSupported": "Modelo {{model}} não suportado",
|
||||
@@ -567,6 +569,13 @@ export const dict = {
|
||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Uso atual para",
|
||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "é $",
|
||||
|
||||
"workspace.redeem.title": "Resgatar Cupom",
|
||||
"workspace.redeem.subtitle": "Resgate um código de cupom para receber créditos ou vantagens.",
|
||||
"workspace.redeem.placeholder": "Digite o código do cupom",
|
||||
"workspace.redeem.redeem": "Resgatar",
|
||||
"workspace.redeem.redeeming": "Resgatando...",
|
||||
"workspace.redeem.success": "Cupom resgatado com sucesso.",
|
||||
|
||||
"workspace.reload.title": "Recarga Automática",
|
||||
"workspace.reload.disabled.before": "A recarga automática está",
|
||||
"workspace.reload.disabled.state": "desativada",
|
||||
|
||||
@@ -11,7 +11,7 @@ export const dict = {
|
||||
"nav.enterprise": "Enterprise",
|
||||
"nav.zen": "Zen",
|
||||
"nav.login": "Log ind",
|
||||
"nav.free": "Gratis",
|
||||
"nav.free": "Download",
|
||||
"nav.home": "Hjem",
|
||||
"nav.openMenu": "Åbn menu",
|
||||
"nav.getStartedFree": "Kom i gang gratis",
|
||||
@@ -251,7 +251,7 @@ export const dict = {
|
||||
|
||||
"go.title": "OpenCode Go | Kodningsmodeller til lav pris for alle",
|
||||
"go.meta.description":
|
||||
"Go starter ved $5 for den første måned, derefter $10/måned, med generøse 5-timers anmodningsgrænser for GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7.",
|
||||
"Go starter ved $5 for den første måned, derefter $10/måned, med generøse 5-timers anmodningsgrænser for GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash.",
|
||||
"go.hero.title": "Kodningsmodeller til lav pris for alle",
|
||||
"go.hero.body":
|
||||
"Go bringer agentisk kodning til programmører over hele verden. Med generøse grænser og pålidelig adgang til de mest kapable open source-modeller, så du kan bygge med kraftfulde agenter uden at bekymre dig om omkostninger eller tilgængelighed.",
|
||||
@@ -263,6 +263,8 @@ export const dict = {
|
||||
"go.cta.promo": "$5 første måned",
|
||||
"go.pricing.body":
|
||||
"Brug med enhver agent. $5 første måned, derefter $10/måned. Tank op med kredit efter behov. Afmeld når som helst.",
|
||||
"go.banner.badge": "3x",
|
||||
"go.banner.text": "Kimi K2.6: brugsgrænsen tredoblet til 27. april",
|
||||
"go.graph.free": "Gratis",
|
||||
"go.graph.freePill": "Big Pickle og gratis modeller",
|
||||
"go.graph.go": "Go",
|
||||
@@ -300,7 +302,7 @@ export const dict = {
|
||||
"go.problem.item2": "Generøse grænser og pålidelig adgang",
|
||||
"go.problem.item3": "Bygget til så mange programmører som muligt",
|
||||
"go.problem.item4":
|
||||
"Inkluderer GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7",
|
||||
"Inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash",
|
||||
"go.how.title": "Hvordan Go virker",
|
||||
"go.how.body":
|
||||
"Go starter ved $5 for den første måned, derefter $10/måned. Du kan bruge det med OpenCode eller enhver agent.",
|
||||
@@ -326,7 +328,7 @@ export const dict = {
|
||||
"go.faq.a2": "Go inkluderer modellerne nedenfor med generøse grænser og pålidelig adgang.",
|
||||
"go.faq.q3": "Er Go det samme som Zen?",
|
||||
"go.faq.a3":
|
||||
"Nej. Zen er pay-as-you-go, mens Go starter ved $5 for den første måned, derefter $10/måned, med generøse grænser og pålidelig adgang til open source-modellerne GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7.",
|
||||
"Nej. Zen er pay-as-you-go, mens Go starter ved $5 for den første måned, derefter $10/måned, med generøse grænser og pålidelig adgang til open source-modellerne GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash.",
|
||||
"go.faq.q4": "Hvad koster Go?",
|
||||
"go.faq.a4.p1.beforePricing": "Go koster",
|
||||
"go.faq.a4.p1.pricingLink": "$5 første måned",
|
||||
@@ -349,7 +351,7 @@ export const dict = {
|
||||
|
||||
"go.faq.q9": "Hvad er forskellen på gratis modeller og Go?",
|
||||
"go.faq.a9":
|
||||
"Gratis modeller inkluderer Big Pickle plus salgsfremmende modeller tilgængelige på det tidspunkt, med en kvote på 200 forespørgsler/dag. Go inkluderer GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 og MiniMax M2.7 med højere anmodningskvoter håndhævet over rullende vinduer (5-timers, ugentlig og månedlig), nogenlunde svarende til $12 pr. 5 timer, $30 pr. uge og $60 pr. måned (faktiske anmodningstal varierer efter model og brug).",
|
||||
"Gratis modeller inkluderer Big Pickle plus salgsfremmende modeller tilgængelige på det tidspunkt, med en kvote på 200 forespørgsler/dag. Go inkluderer GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro og DeepSeek V4 Flash med højere anmodningskvoter håndhævet over rullende vinduer (5-timers, ugentlig og månedlig), nogenlunde svarende til $12 pr. 5 timer, $30 pr. uge og $60 pr. måned (faktiske anmodningstal varierer efter model og brug).",
|
||||
|
||||
"zen.api.error.rateLimitExceeded": "Hastighedsgrænse overskredet. Prøv venligst igen senere.",
|
||||
"zen.api.error.modelNotSupported": "Model {{model}} understøttes ikke",
|
||||
@@ -563,6 +565,13 @@ export const dict = {
|
||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Nuværende brug for",
|
||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "er $",
|
||||
|
||||
"workspace.redeem.title": "Indløs kupon",
|
||||
"workspace.redeem.subtitle": "Indløs en kuponkode for at få kreditter eller fordele.",
|
||||
"workspace.redeem.placeholder": "Indtast kuponkode",
|
||||
"workspace.redeem.redeem": "Indløs",
|
||||
"workspace.redeem.redeeming": "Indløser...",
|
||||
"workspace.redeem.success": "Kuponen blev indløst.",
|
||||
|
||||
"workspace.reload.title": "Automatisk genopfyldning",
|
||||
"workspace.reload.disabled.before": "Automatisk genopfyldning er",
|
||||
"workspace.reload.disabled.state": "deaktiveret",
|
||||
|
||||
@@ -11,7 +11,7 @@ export const dict = {
|
||||
"nav.enterprise": "Enterprise",
|
||||
"nav.zen": "Zen",
|
||||
"nav.login": "Anmelden",
|
||||
"nav.free": "Kostenlos",
|
||||
"nav.free": "Download",
|
||||
"nav.home": "Startseite",
|
||||
"nav.openMenu": "Menü öffnen",
|
||||
"nav.getStartedFree": "Kostenlos starten",
|
||||
@@ -253,7 +253,7 @@ export const dict = {
|
||||
|
||||
"go.title": "OpenCode Go | Kostengünstige Coding-Modelle für alle",
|
||||
"go.meta.description":
|
||||
"Go beginnt bei $5 für den ersten Monat, danach $10/Monat, mit großzügigen 5-Stunden-Anfragelimits für GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7.",
|
||||
"Go beginnt bei $5 für den ersten Monat, danach $10/Monat, mit großzügigen 5-Stunden-Anfragelimits für GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro und DeepSeek V4 Flash.",
|
||||
"go.hero.title": "Kostengünstige Coding-Modelle für alle",
|
||||
"go.hero.body":
|
||||
"Go bringt Agentic Coding zu Programmierern auf der ganzen Welt. Mit großzügigen Limits und zuverlässigem Zugang zu den leistungsfähigsten Open-Source-Modellen, damit du mit leistungsstarken Agenten entwickeln kannst, ohne dir Gedanken über Kosten oder Verfügbarkeit zu machen.",
|
||||
@@ -265,6 +265,8 @@ export const dict = {
|
||||
"go.cta.promo": "$5 im ersten Monat",
|
||||
"go.pricing.body":
|
||||
"Mit jedem Agenten nutzbar. $5 im ersten Monat, danach $10/Monat. Guthaben bei Bedarf aufladen. Jederzeit kündbar.",
|
||||
"go.banner.badge": "3x",
|
||||
"go.banner.text": "Kimi K2.6: Nutzungslimit bis zum 27. April verdreifacht",
|
||||
"go.graph.free": "Kostenlos",
|
||||
"go.graph.freePill": "Big Pickle und kostenlose Modelle",
|
||||
"go.graph.go": "Go",
|
||||
@@ -302,7 +304,7 @@ export const dict = {
|
||||
"go.problem.item2": "Großzügige Limits und zuverlässiger Zugang",
|
||||
"go.problem.item3": "Für so viele Programmierer wie möglich gebaut",
|
||||
"go.problem.item4":
|
||||
"Beinhaltet GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7",
|
||||
"Beinhaltet GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro und DeepSeek V4 Flash",
|
||||
"go.how.title": "Wie Go funktioniert",
|
||||
"go.how.body":
|
||||
"Go beginnt bei $5 für den ersten Monat, danach $10/Monat. Du kannst es mit OpenCode oder jedem Agenten nutzen.",
|
||||
@@ -328,7 +330,7 @@ export const dict = {
|
||||
"go.faq.a2": "Go umfasst die unten aufgeführten Modelle mit großzügigen Limits und zuverlässigem Zugriff.",
|
||||
"go.faq.q3": "Ist Go dasselbe wie Zen?",
|
||||
"go.faq.a3":
|
||||
"Nein. Zen ist Pay-as-you-go, während Go bei $5 für den ersten Monat beginnt, danach $10/Monat, mit großzügigen Limits und zuverlässigem Zugang zu den Open-Source-Modellen GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7.",
|
||||
"Nein. Zen ist Pay-as-you-go, während Go bei $5 für den ersten Monat beginnt, danach $10/Monat, mit großzügigen Limits und zuverlässigem Zugang zu den Open-Source-Modellen GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro und DeepSeek V4 Flash.",
|
||||
"go.faq.q4": "Wie viel kostet Go?",
|
||||
"go.faq.a4.p1.beforePricing": "Go kostet",
|
||||
"go.faq.a4.p1.pricingLink": "$5 im ersten Monat",
|
||||
@@ -352,7 +354,7 @@ export const dict = {
|
||||
|
||||
"go.faq.q9": "Was ist der Unterschied zwischen kostenlosen Modellen und Go?",
|
||||
"go.faq.a9":
|
||||
"Kostenlose Modelle beinhalten Big Pickle sowie Werbemodelle, die zum jeweiligen Zeitpunkt verfügbar sind, mit einem Kontingent von 200 Anfragen/Tag. Go beinhaltet GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 und MiniMax M2.7 mit höheren Anfragekontingenten, die über rollierende Zeitfenster (5 Stunden, wöchentlich und monatlich) durchgesetzt werden, grob äquivalent zu $12 pro 5 Stunden, $30 pro Woche und $60 pro Monat (tatsächliche Anfragezahlen variieren je nach Modell und Nutzung).",
|
||||
"Kostenlose Modelle beinhalten Big Pickle sowie Werbemodelle, die zum jeweiligen Zeitpunkt verfügbar sind, mit einem Kontingent von 200 Anfragen/Tag. Go beinhaltet GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro und DeepSeek V4 Flash mit höheren Anfragekontingenten, die über rollierende Zeitfenster (5 Stunden, wöchentlich und monatlich) durchgesetzt werden, grob äquivalent zu $12 pro 5 Stunden, $30 pro Woche und $60 pro Monat (tatsächliche Anfragezahlen variieren je nach Modell und Nutzung).",
|
||||
|
||||
"zen.api.error.rateLimitExceeded": "Ratenlimit überschritten. Bitte versuche es später erneut.",
|
||||
"zen.api.error.modelNotSupported": "Modell {{model}} wird nicht unterstützt",
|
||||
@@ -566,6 +568,13 @@ export const dict = {
|
||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Aktuelle Nutzung für",
|
||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "ist $",
|
||||
|
||||
"workspace.redeem.title": "Gutschein einlösen",
|
||||
"workspace.redeem.subtitle": "Löse einen Gutscheincode ein, um Guthaben oder Vorteile zu erhalten.",
|
||||
"workspace.redeem.placeholder": "Gutscheincode eingeben",
|
||||
"workspace.redeem.redeem": "Einlösen",
|
||||
"workspace.redeem.redeeming": "Wird eingelöst...",
|
||||
"workspace.redeem.success": "Gutschein erfolgreich eingelöst.",
|
||||
|
||||
"workspace.reload.title": "Auto-Reload",
|
||||
"workspace.reload.disabled.before": "Auto-Reload ist",
|
||||
"workspace.reload.disabled.state": "deaktiviert",
|
||||
|
||||
@@ -8,7 +8,7 @@ export const dict = {
|
||||
"nav.zen": "Zen",
|
||||
"nav.go": "Go",
|
||||
"nav.login": "Login",
|
||||
"nav.free": "Free",
|
||||
"nav.free": "Download",
|
||||
"nav.home": "Home",
|
||||
"nav.openMenu": "Open menu",
|
||||
"nav.getStartedFree": "Get started for free",
|
||||
@@ -248,7 +248,9 @@ export const dict = {
|
||||
|
||||
"go.title": "OpenCode Go | Low cost coding models for everyone",
|
||||
"go.meta.description":
|
||||
"Go starts at $5 for your first month, then $10/month, with generous 5-hour request limits for GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7.",
|
||||
"Go starts at $5 for your first month, then $10/month, with generous 5-hour request limits for GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, and DeepSeek V4 Flash.",
|
||||
"go.banner.badge": "3x",
|
||||
"go.banner.text": "Kimi K2.6 gets 3× usage limits through April 27",
|
||||
"go.hero.title": "Low cost coding models for everyone",
|
||||
"go.hero.body":
|
||||
"Go brings agentic coding to programmers around the world. Offering generous limits and reliable access to the most capable open-source models, so you can build with powerful agents without worrying about cost or availability.",
|
||||
@@ -296,7 +298,7 @@ export const dict = {
|
||||
"go.problem.item2": "Generous limits and reliable access",
|
||||
"go.problem.item3": "Built for as many programmers as possible",
|
||||
"go.problem.item4":
|
||||
"Includes GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7",
|
||||
"Includes GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, and DeepSeek V4 Flash",
|
||||
"go.how.title": "How Go works",
|
||||
"go.how.body": "Go starts at $5 for your first month, then $10/month. You can use it with OpenCode or any agent.",
|
||||
"go.how.step1.title": "Create an account",
|
||||
@@ -321,7 +323,7 @@ export const dict = {
|
||||
"go.faq.a2": "Go includes the models listed below, with generous limits and reliable access.",
|
||||
"go.faq.q3": "Is Go the same as Zen?",
|
||||
"go.faq.a3":
|
||||
"No. Zen is pay-as-you-go, while Go starts at $5 for your first month, then $10/month, with generous limits and reliable access to open-source models GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7.",
|
||||
"No. Zen is pay-as-you-go, while Go starts at $5 for your first month, then $10/month, with generous limits and reliable access to open-source models GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, and DeepSeek V4 Flash.",
|
||||
"go.faq.q4": "How much does Go cost?",
|
||||
"go.faq.a4.p1.beforePricing": "Go costs",
|
||||
"go.faq.a4.p1.pricingLink": "$5 first month",
|
||||
@@ -345,7 +347,7 @@ export const dict = {
|
||||
|
||||
"go.faq.q9": "What is the difference between free models and Go?",
|
||||
"go.faq.a9":
|
||||
"Free models include Big Pickle plus promotional models available at the time, with a quota of 200 requests/day. Go includes GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, and MiniMax M2.7 with higher request quotas enforced across rolling windows (5-hour, weekly, and monthly), roughly equivalent to $12 per 5 hours, $30 per week, and $60 per month (actual request counts vary by model and usage).",
|
||||
"Free models include Big Pickle plus promotional models available at the time, with a quota of 200 requests/day. Go includes GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, and DeepSeek V4 Flash with higher request quotas enforced across rolling windows (5-hour, weekly, and monthly), roughly equivalent to $12 per 5 hours, $30 per week, and $60 per month (actual request counts vary by model and usage).",
|
||||
|
||||
"zen.api.error.rateLimitExceeded": "Rate limit exceeded. Please try again later.",
|
||||
"zen.api.error.modelNotSupported": "Model {{model}} not supported",
|
||||
@@ -559,6 +561,13 @@ export const dict = {
|
||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Current usage for",
|
||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "is $",
|
||||
|
||||
"workspace.redeem.title": "Redeem Coupon",
|
||||
"workspace.redeem.subtitle": "Redeem a coupon code to claim credits or perks.",
|
||||
"workspace.redeem.placeholder": "Enter coupon code",
|
||||
"workspace.redeem.redeem": "Redeem",
|
||||
"workspace.redeem.redeeming": "Redeeming...",
|
||||
"workspace.redeem.success": "Coupon redeemed successfully.",
|
||||
|
||||
"workspace.reload.title": "Auto Reload",
|
||||
"workspace.reload.disabled.before": "Auto reload is",
|
||||
"workspace.reload.disabled.state": "disabled",
|
||||
|
||||
@@ -11,7 +11,7 @@ export const dict = {
|
||||
"nav.enterprise": "Enterprise",
|
||||
"nav.zen": "Zen",
|
||||
"nav.login": "Iniciar sesión",
|
||||
"nav.free": "Gratis",
|
||||
"nav.free": "Descargar",
|
||||
"nav.home": "Inicio",
|
||||
"nav.openMenu": "Abrir menú",
|
||||
"nav.getStartedFree": "Empezar gratis",
|
||||
@@ -254,7 +254,7 @@ export const dict = {
|
||||
|
||||
"go.title": "OpenCode Go | Modelos de programación de bajo coste para todos",
|
||||
"go.meta.description":
|
||||
"Go comienza en $5 el primer mes, luego 10 $/mes, con generosos límites de solicitudes de 5 horas para GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7.",
|
||||
"Go comienza en $5 el primer mes, luego 10 $/mes, con generosos límites de solicitudes de 5 horas para GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro y DeepSeek V4 Flash.",
|
||||
"go.hero.title": "Modelos de programación de bajo coste para todos",
|
||||
"go.hero.body":
|
||||
"Go lleva la programación agéntica a programadores de todo el mundo. Ofrece límites generosos y acceso fiable a los modelos de código abierto más capaces, para que puedas crear con agentes potentes sin preocuparte por el coste o la disponibilidad.",
|
||||
@@ -266,6 +266,8 @@ export const dict = {
|
||||
"go.cta.promo": "$5 el primer mes",
|
||||
"go.pricing.body":
|
||||
"Úsalo con cualquier agente. $5 el primer mes, luego 10 $/mes. Recarga crédito si es necesario. Cancela en cualquier momento.",
|
||||
"go.banner.badge": "3x",
|
||||
"go.banner.text": "Kimi K2.6: límite de uso triplicado hasta el 27 de abril",
|
||||
"go.graph.free": "Gratis",
|
||||
"go.graph.freePill": "Big Pickle y modelos gratuitos",
|
||||
"go.graph.go": "Go",
|
||||
@@ -304,7 +306,7 @@ export const dict = {
|
||||
"go.problem.item2": "Límites generosos y acceso fiable",
|
||||
"go.problem.item3": "Creado para tantos programadores como sea posible",
|
||||
"go.problem.item4":
|
||||
"Incluye GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7",
|
||||
"Incluye GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro y DeepSeek V4 Flash",
|
||||
"go.how.title": "Cómo funciona Go",
|
||||
"go.how.body": "Go comienza en $5 el primer mes, luego 10 $/mes. Puedes usarlo con OpenCode o cualquier agente.",
|
||||
"go.how.step1.title": "Crear una cuenta",
|
||||
@@ -329,7 +331,7 @@ export const dict = {
|
||||
"go.faq.a2": "Go incluye los modelos que se indican abajo, con límites generosos y acceso confiable.",
|
||||
"go.faq.q3": "¿Es Go lo mismo que Zen?",
|
||||
"go.faq.a3":
|
||||
"No. Zen es pago por uso, mientras que Go comienza en $5 el primer mes, luego 10 $/mes, con límites generosos y acceso fiable a los modelos de código abierto GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7.",
|
||||
"No. Zen es pago por uso, mientras que Go comienza en $5 el primer mes, luego 10 $/mes, con límites generosos y acceso fiable a los modelos de código abierto GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro y DeepSeek V4 Flash.",
|
||||
"go.faq.q4": "¿Cuánto cuesta Go?",
|
||||
"go.faq.a4.p1.beforePricing": "Go cuesta",
|
||||
"go.faq.a4.p1.pricingLink": "$5 el primer mes",
|
||||
@@ -353,7 +355,7 @@ export const dict = {
|
||||
|
||||
"go.faq.q9": "¿Cuál es la diferencia entre los modelos gratuitos y Go?",
|
||||
"go.faq.a9":
|
||||
"Los modelos gratuitos incluyen Big Pickle más modelos promocionales disponibles en el momento, con una cuota de 200 solicitudes/día. Go incluye GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 y MiniMax M2.7 con cuotas de solicitud más altas aplicadas a través de ventanas móviles (5 horas, semanal y mensual), aproximadamente equivalente a 12 $ por 5 horas, 30 $ por semana y 60 $ por mes (los recuentos reales de solicitudes varían según el modelo y el uso).",
|
||||
"Los modelos gratuitos incluyen Big Pickle más modelos promocionales disponibles en el momento, con una cuota de 200 solicitudes/día. Go incluye GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro y DeepSeek V4 Flash con cuotas de solicitud más altas aplicadas a través de ventanas móviles (5 horas, semanal y mensual), aproximadamente equivalente a 12 $ por 5 horas, 30 $ por semana y 60 $ por mes (los recuentos reales de solicitudes varían según el modelo y el uso).",
|
||||
|
||||
"zen.api.error.rateLimitExceeded": "Límite de tasa excedido. Por favor, inténtalo de nuevo más tarde.",
|
||||
"zen.api.error.modelNotSupported": "Modelo {{model}} no soportado",
|
||||
@@ -567,6 +569,13 @@ export const dict = {
|
||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Uso actual para",
|
||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "es $",
|
||||
|
||||
"workspace.redeem.title": "Canjear cupón",
|
||||
"workspace.redeem.subtitle": "Canjea un código de cupón para obtener crédito o beneficios.",
|
||||
"workspace.redeem.placeholder": "Introduce el código del cupón",
|
||||
"workspace.redeem.redeem": "Canjear",
|
||||
"workspace.redeem.redeeming": "Canjeando...",
|
||||
"workspace.redeem.success": "Cupón canjeado correctamente.",
|
||||
|
||||
"workspace.reload.title": "Auto Recarga",
|
||||
"workspace.reload.disabled.before": "La auto recarga está",
|
||||
"workspace.reload.disabled.state": "deshabilitada",
|
||||
|
||||
@@ -12,7 +12,7 @@ export const dict = {
|
||||
"nav.enterprise": "Entreprise",
|
||||
"nav.zen": "Zen",
|
||||
"nav.login": "Se connecter",
|
||||
"nav.free": "Gratuit",
|
||||
"nav.free": "Télécharger",
|
||||
"nav.home": "Accueil",
|
||||
"nav.openMenu": "Ouvrir le menu",
|
||||
"nav.getStartedFree": "Commencer gratuitement",
|
||||
@@ -255,7 +255,7 @@ export const dict = {
|
||||
|
||||
"go.title": "OpenCode Go | Modèles de code à faible coût pour tous",
|
||||
"go.meta.description":
|
||||
"Go commence à $5 pour le premier mois, puis 10 $/mois, avec des limites de requêtes généreuses sur 5 heures pour GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7.",
|
||||
"Go commence à $5 pour le premier mois, puis 10 $/mois, avec des limites de requêtes généreuses sur 5 heures pour GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro et DeepSeek V4 Flash.",
|
||||
"go.hero.title": "Modèles de code à faible coût pour tous",
|
||||
"go.hero.body":
|
||||
"Go apporte le codage agentique aux programmeurs du monde entier. Offrant des limites généreuses et un accès fiable aux modèles open source les plus capables, pour que vous puissiez construire avec des agents puissants sans vous soucier du coût ou de la disponibilité.",
|
||||
@@ -267,6 +267,8 @@ export const dict = {
|
||||
"go.cta.promo": "$5 le premier mois",
|
||||
"go.pricing.body":
|
||||
"Utilisez-le avec n'importe quel agent. $5 le premier mois, puis 10 $/mois. Rechargez du crédit si nécessaire. Annulez à tout moment.",
|
||||
"go.banner.badge": "3x",
|
||||
"go.banner.text": "Kimi K2.6 : limites d’utilisation triplées jusqu’au 27 avril",
|
||||
"go.graph.free": "Gratuit",
|
||||
"go.graph.freePill": "Big Pickle et modèles gratuits",
|
||||
"go.graph.go": "Go",
|
||||
@@ -304,7 +306,7 @@ export const dict = {
|
||||
"go.problem.item2": "Limites généreuses et accès fiable",
|
||||
"go.problem.item3": "Conçu pour autant de programmeurs que possible",
|
||||
"go.problem.item4":
|
||||
"Inclut GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7",
|
||||
"Inclut GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro et DeepSeek V4 Flash",
|
||||
"go.how.title": "Comment fonctionne Go",
|
||||
"go.how.body":
|
||||
"Go commence à $5 pour le premier mois, puis 10 $/mois. Vous pouvez l'utiliser avec OpenCode ou n'importe quel agent.",
|
||||
@@ -330,7 +332,7 @@ export const dict = {
|
||||
"go.faq.a2": "Go inclut les modèles ci-dessous, avec des limites généreuses et un accès fiable.",
|
||||
"go.faq.q3": "Est-ce que Go est la même chose que Zen ?",
|
||||
"go.faq.a3":
|
||||
"Non. Zen est un paiement à l'utilisation, tandis que Go commence à $5 pour le premier mois, puis 10 $/mois, avec des limites généreuses et un accès fiable aux modèles open source GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7.",
|
||||
"Non. Zen est un paiement à l'utilisation, tandis que Go commence à $5 pour le premier mois, puis 10 $/mois, avec des limites généreuses et un accès fiable aux modèles open source GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro et DeepSeek V4 Flash.",
|
||||
"go.faq.q4": "Combien coûte Go ?",
|
||||
"go.faq.a4.p1.beforePricing": "Go coûte",
|
||||
"go.faq.a4.p1.pricingLink": "$5 le premier mois",
|
||||
@@ -353,7 +355,7 @@ export const dict = {
|
||||
"Oui, vous pouvez utiliser Go avec n'importe quel agent. Suivez les instructions de configuration dans votre agent de code préféré.",
|
||||
"go.faq.q9": "Quelle est la différence entre les modèles gratuits et Go ?",
|
||||
"go.faq.a9":
|
||||
"Les modèles gratuits incluent Big Pickle ainsi que des modèles promotionnels disponibles à ce moment-là, avec un quota de 200 requêtes/jour. Go inclut GLM-5.1, GLM-5, Kimi K2.5, MiMo-V2-Pro, MiMo-V2-Omni, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5 et MiniMax M2.7 avec des quotas de requêtes plus élevés appliqués sur des fenêtres glissantes (5 heures, hebdomadaire et mensuelle), à peu près équivalent à 12 $ par 5 heures, 30 $ par semaine et 60 $ par mois (le nombre réel de requêtes varie selon le modèle et l'utilisation).",
|
||||
"Les modèles gratuits incluent Big Pickle ainsi que des modèles promotionnels disponibles à ce moment-là, avec un quota de 200 requêtes/jour. Go inclut GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro et DeepSeek V4 Flash avec des quotas de requêtes plus élevés appliqués sur des fenêtres glissantes (5 heures, hebdomadaire et mensuelle), à peu près équivalent à 12 $ par 5 heures, 30 $ par semaine et 60 $ par mois (le nombre réel de requêtes varie selon le modèle et l'utilisation).",
|
||||
|
||||
"zen.api.error.rateLimitExceeded": "Limite de débit dépassée. Veuillez réessayer plus tard.",
|
||||
"zen.api.error.modelNotSupported": "Modèle {{model}} non pris en charge",
|
||||
@@ -569,6 +571,13 @@ export const dict = {
|
||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "L'utilisation actuelle pour",
|
||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "est de",
|
||||
|
||||
"workspace.redeem.title": "Utiliser un coupon",
|
||||
"workspace.redeem.subtitle": "Utilisez un code promo pour obtenir du crédit ou des avantages.",
|
||||
"workspace.redeem.placeholder": "Saisissez le code promo",
|
||||
"workspace.redeem.redeem": "Utiliser",
|
||||
"workspace.redeem.redeeming": "Utilisation...",
|
||||
"workspace.redeem.success": "Coupon utilisé avec succès.",
|
||||
|
||||
"workspace.reload.title": "Rechargement automatique",
|
||||
"workspace.reload.disabled.before": "Le rechargement automatique est",
|
||||
"workspace.reload.disabled.state": "désactivé",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user