Compare commits
132 Commits
bash-tweak
...
docs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c503b9c70 | ||
|
|
659f23de30 | ||
|
|
2252b5ca1b | ||
|
|
c78dad8db5 | ||
|
|
0569e8652c | ||
|
|
f2d5b32e52 | ||
|
|
b2f5ea7c30 | ||
|
|
8eb8f1a16c | ||
|
|
ad93d50ab7 | ||
|
|
73c5c328a8 | ||
|
|
72a13212e2 | ||
|
|
78bcf35f37 | ||
|
|
3a3ee3ecfd | ||
|
|
34e045c275 | ||
|
|
e187918ce0 | ||
|
|
7ac17c7833 | ||
|
|
b05d5b30fb | ||
|
|
57c08b01b7 | ||
|
|
08efb9cdf6 | ||
|
|
8b51da768c | ||
|
|
862407c674 | ||
|
|
a381aa7e0d | ||
|
|
4dcda3d53d | ||
|
|
479cca29a5 | ||
|
|
e38814c597 | ||
|
|
4d42daa9a3 | ||
|
|
130345bd5d | ||
|
|
0baee00be4 | ||
|
|
e0acd5d361 | ||
|
|
1e7d78a215 | ||
|
|
7a6cb85617 | ||
|
|
20530104ce | ||
|
|
d22754dd68 | ||
|
|
db0e1ebb80 | ||
|
|
e83a47debe | ||
|
|
eed48e76de | ||
|
|
ac70c1e813 | ||
|
|
ac0bed16a2 | ||
|
|
fab8ab2840 | ||
|
|
09ff8eba00 | ||
|
|
9bd2ea5e5f | ||
|
|
aa525482ae | ||
|
|
285605737d | ||
|
|
4201fe6e01 | ||
|
|
203f3312ee | ||
|
|
0c77c46dc7 | ||
|
|
52bb43eebd | ||
|
|
e020f5355e | ||
|
|
9b86d4e595 | ||
|
|
f3d3b41a3f | ||
|
|
a959199f09 | ||
|
|
5e3a59d5a2 | ||
|
|
9f23d85e20 | ||
|
|
54e15b38ea | ||
|
|
d66b903e7f | ||
|
|
4425c66732 | ||
|
|
0dd0250285 | ||
|
|
c347056246 | ||
|
|
2a5255ac8f | ||
|
|
d9175be989 | ||
|
|
cebbfcfbaa | ||
|
|
de415be4f6 | ||
|
|
e8ce113b7f | ||
|
|
8ca02b7664 | ||
|
|
3f5bb21f16 | ||
|
|
fe114c41b5 | ||
|
|
d90fd8a5d7 | ||
|
|
9363c15b4a | ||
|
|
3325823f23 | ||
|
|
4b4d8da1ad | ||
|
|
d531dff8d3 | ||
|
|
923bf36593 | ||
|
|
d6e499dd48 | ||
|
|
aec1497c6e | ||
|
|
f5a77c8cd8 | ||
|
|
bc524eeb44 | ||
|
|
725f658260 | ||
|
|
af1080dd42 | ||
|
|
63e54541fe | ||
|
|
c3f7a88c1c | ||
|
|
586a8b7b31 | ||
|
|
981744f802 | ||
|
|
a3bb4a3c85 | ||
|
|
06ba1f76dc | ||
|
|
076c8b2ca1 | ||
|
|
9a90939ac4 | ||
|
|
123a136093 | ||
|
|
4126fedbd4 | ||
|
|
145d185e6f | ||
|
|
6b32667c7d | ||
|
|
d8401e1937 | ||
|
|
55d6fcc350 | ||
|
|
9ff39503e9 | ||
|
|
f96c181afd | ||
|
|
f9b75a09df | ||
|
|
6111ed79b1 | ||
|
|
4cf2322b7f | ||
|
|
2c6fcc5dc1 | ||
|
|
81ee8541ab | ||
|
|
5b3550ab9f | ||
|
|
4fabce58d8 | ||
|
|
da7edb5f5c | ||
|
|
bf0f85e37f | ||
|
|
7b52160bff | ||
|
|
fde97ec4a7 | ||
|
|
ea7ec60f51 | ||
|
|
6667856ba5 | ||
|
|
13b2cf50ae | ||
|
|
93b0abfce9 | ||
|
|
f7e4c47113 | ||
|
|
509e43d6f8 | ||
|
|
e693192e06 | ||
|
|
ec27759f90 | ||
|
|
9c938eec73 | ||
|
|
238b907dd8 | ||
|
|
c16d8c6db8 | ||
|
|
9856e3b798 | ||
|
|
1d089272c8 | ||
|
|
c30b1130ee | ||
|
|
40ca222d09 | ||
|
|
0ecccbfd17 | ||
|
|
3f4862ced6 | ||
|
|
1574e2457b | ||
|
|
af33212f77 | ||
|
|
4eb82e8c04 | ||
|
|
a45f0aac90 | ||
|
|
eb4afdca65 | ||
|
|
9391749577 | ||
|
|
36a25660e9 | ||
|
|
d9fe722da1 | ||
|
|
da722e7db9 | ||
|
|
75a4dcbce8 |
4
.github/workflows/format.yml
vendored
@@ -18,7 +18,8 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
ref: ${{ github.head_ref || github.ref }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
|
||||
ref: ${{ github.event.pull_request.head.ref || github.ref_name }}
|
||||
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
@@ -28,3 +29,4 @@ jobs:
|
||||
./script/format.ts
|
||||
env:
|
||||
CI: true
|
||||
PUSH_BRANCH: ${{ github.event.pull_request.head.ref || github.ref_name }}
|
||||
|
||||
35
.github/workflows/publish.yml
vendored
@@ -26,7 +26,7 @@ permissions:
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
if: github.repository == 'sst/opencode'
|
||||
if: github.repository == 'sst/opencode' && github.ref == 'refs/heads/dev'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
@@ -82,7 +82,9 @@ jobs:
|
||||
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
|
||||
|
||||
publish-tauri:
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
settings:
|
||||
- host: macos-latest
|
||||
@@ -99,6 +101,26 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: apple-actions/import-codesign-certs@v2
|
||||
if: ${{ runner.os == 'macOS' }}
|
||||
with:
|
||||
keychain: build
|
||||
p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
|
||||
- name: Verify Certificate
|
||||
if: ${{ runner.os == 'macOS' }}
|
||||
run: |
|
||||
CERT_INFO=$(security find-identity -v -p codesigning build.keychain | grep "Developer ID Application")
|
||||
CERT_ID=$(echo "$CERT_INFO" | awk -F'"' '{print $2}')
|
||||
echo "CERT_ID=$CERT_ID" >> $GITHUB_ENV
|
||||
echo "Certificate imported."
|
||||
|
||||
- name: Setup Apple API Key
|
||||
if: ${{ runner.os == 'macOS' }}
|
||||
run: |
|
||||
echo "${{ secrets.APPLE_API_KEY_PATH }}" > $RUNNER_TEMP/apple-api-key.p8
|
||||
|
||||
- run: git fetch --force --tags
|
||||
|
||||
- uses: ./.github/actions/setup-bun
|
||||
@@ -144,12 +166,17 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAURI_BUNDLER_NEW_APPIMAGE_FORMAT: true
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ env.CERT_ID }}
|
||||
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
||||
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
|
||||
APPLE_API_KEY_PATH: ${{ runner.temp }}/apple-api-key.p8
|
||||
with:
|
||||
projectPath: packages/tauri
|
||||
uploadWorkflowArtifacts: true
|
||||
tauriScript: ${{ (startsWith(matrix.settings.host, 'ubuntu') && 'cargo tauri') || '' }}
|
||||
args: --target ${{ matrix.settings.target }}
|
||||
updaterJsonPreferNsis: true
|
||||
releaseDraft: true
|
||||
tagName: ${{ inputs.version }}
|
||||
releaseName: ${{ inputs.version }}
|
||||
# releaseId: TODO
|
||||
|
||||
326
STATS.md
@@ -1,164 +1,166 @@
|
||||
# Download Stats
|
||||
|
||||
| Date | GitHub Downloads | npm Downloads | Total |
|
||||
| ---------- | ----------------- | ----------------- | ------------------- |
|
||||
| 2025-06-29 | 18,789 (+0) | 39,420 (+0) | 58,209 (+0) |
|
||||
| 2025-06-30 | 20,127 (+1,338) | 41,059 (+1,639) | 61,186 (+2,977) |
|
||||
| 2025-07-01 | 22,108 (+1,981) | 43,745 (+2,686) | 65,853 (+4,667) |
|
||||
| 2025-07-02 | 24,814 (+2,706) | 46,168 (+2,423) | 70,982 (+5,129) |
|
||||
| 2025-07-03 | 27,834 (+3,020) | 49,955 (+3,787) | 77,789 (+6,807) |
|
||||
| 2025-07-04 | 30,608 (+2,774) | 54,758 (+4,803) | 85,366 (+7,577) |
|
||||
| 2025-07-05 | 32,524 (+1,916) | 58,371 (+3,613) | 90,895 (+5,529) |
|
||||
| 2025-07-06 | 33,766 (+1,242) | 59,694 (+1,323) | 93,460 (+2,565) |
|
||||
| 2025-07-08 | 38,052 (+4,286) | 64,468 (+4,774) | 102,520 (+9,060) |
|
||||
| 2025-07-09 | 40,924 (+2,872) | 67,935 (+3,467) | 108,859 (+6,339) |
|
||||
| 2025-07-10 | 43,796 (+2,872) | 71,402 (+3,467) | 115,198 (+6,339) |
|
||||
| 2025-07-11 | 46,982 (+3,186) | 77,462 (+6,060) | 124,444 (+9,246) |
|
||||
| 2025-07-12 | 49,302 (+2,320) | 82,177 (+4,715) | 131,479 (+7,035) |
|
||||
| 2025-07-13 | 50,803 (+1,501) | 86,394 (+4,217) | 137,197 (+5,718) |
|
||||
| 2025-07-14 | 53,283 (+2,480) | 87,860 (+1,466) | 141,143 (+3,946) |
|
||||
| 2025-07-15 | 57,590 (+4,307) | 91,036 (+3,176) | 148,626 (+7,483) |
|
||||
| 2025-07-16 | 62,313 (+4,723) | 95,258 (+4,222) | 157,571 (+8,945) |
|
||||
| 2025-07-17 | 66,684 (+4,371) | 100,048 (+4,790) | 166,732 (+9,161) |
|
||||
| 2025-07-18 | 70,379 (+3,695) | 102,587 (+2,539) | 172,966 (+6,234) |
|
||||
| 2025-07-19 | 73,497 (+3,117) | 105,904 (+3,317) | 179,401 (+6,434) |
|
||||
| 2025-07-20 | 76,453 (+2,956) | 109,044 (+3,140) | 185,497 (+6,096) |
|
||||
| 2025-07-21 | 80,197 (+3,744) | 113,537 (+4,493) | 193,734 (+8,237) |
|
||||
| 2025-07-22 | 84,251 (+4,054) | 118,073 (+4,536) | 202,324 (+8,590) |
|
||||
| 2025-07-23 | 88,589 (+4,338) | 121,436 (+3,363) | 210,025 (+7,701) |
|
||||
| 2025-07-24 | 92,469 (+3,880) | 124,091 (+2,655) | 216,560 (+6,535) |
|
||||
| 2025-07-25 | 96,417 (+3,948) | 126,985 (+2,894) | 223,402 (+6,842) |
|
||||
| 2025-07-26 | 100,646 (+4,229) | 131,411 (+4,426) | 232,057 (+8,655) |
|
||||
| 2025-07-27 | 102,644 (+1,998) | 134,736 (+3,325) | 237,380 (+5,323) |
|
||||
| 2025-07-28 | 105,446 (+2,802) | 136,016 (+1,280) | 241,462 (+4,082) |
|
||||
| 2025-07-29 | 108,998 (+3,552) | 137,542 (+1,526) | 246,540 (+5,078) |
|
||||
| 2025-07-30 | 113,544 (+4,546) | 140,317 (+2,775) | 253,861 (+7,321) |
|
||||
| 2025-07-31 | 118,339 (+4,795) | 143,344 (+3,027) | 261,683 (+7,822) |
|
||||
| 2025-08-01 | 123,539 (+5,200) | 146,680 (+3,336) | 270,219 (+8,536) |
|
||||
| 2025-08-02 | 127,864 (+4,325) | 149,236 (+2,556) | 277,100 (+6,881) |
|
||||
| 2025-08-03 | 131,397 (+3,533) | 150,451 (+1,215) | 281,848 (+4,748) |
|
||||
| 2025-08-04 | 136,266 (+4,869) | 153,260 (+2,809) | 289,526 (+7,678) |
|
||||
| 2025-08-05 | 141,596 (+5,330) | 155,752 (+2,492) | 297,348 (+7,822) |
|
||||
| 2025-08-06 | 147,067 (+5,471) | 158,309 (+2,557) | 305,376 (+8,028) |
|
||||
| 2025-08-07 | 152,591 (+5,524) | 160,889 (+2,580) | 313,480 (+8,104) |
|
||||
| 2025-08-08 | 158,187 (+5,596) | 163,448 (+2,559) | 321,635 (+8,155) |
|
||||
| 2025-08-09 | 162,770 (+4,583) | 165,721 (+2,273) | 328,491 (+6,856) |
|
||||
| 2025-08-10 | 165,695 (+2,925) | 167,109 (+1,388) | 332,804 (+4,313) |
|
||||
| 2025-08-11 | 169,297 (+3,602) | 167,953 (+844) | 337,250 (+4,446) |
|
||||
| 2025-08-12 | 176,307 (+7,010) | 171,876 (+3,923) | 348,183 (+10,933) |
|
||||
| 2025-08-13 | 182,997 (+6,690) | 177,182 (+5,306) | 360,179 (+11,996) |
|
||||
| 2025-08-14 | 189,063 (+6,066) | 179,741 (+2,559) | 368,804 (+8,625) |
|
||||
| 2025-08-15 | 193,608 (+4,545) | 181,792 (+2,051) | 375,400 (+6,596) |
|
||||
| 2025-08-16 | 198,118 (+4,510) | 184,558 (+2,766) | 382,676 (+7,276) |
|
||||
| 2025-08-17 | 201,299 (+3,181) | 186,269 (+1,711) | 387,568 (+4,892) |
|
||||
| 2025-08-18 | 204,559 (+3,260) | 187,399 (+1,130) | 391,958 (+4,390) |
|
||||
| 2025-08-19 | 209,814 (+5,255) | 189,668 (+2,269) | 399,482 (+7,524) |
|
||||
| 2025-08-20 | 214,497 (+4,683) | 191,481 (+1,813) | 405,978 (+6,496) |
|
||||
| 2025-08-21 | 220,465 (+5,968) | 194,784 (+3,303) | 415,249 (+9,271) |
|
||||
| 2025-08-22 | 225,899 (+5,434) | 197,204 (+2,420) | 423,103 (+7,854) |
|
||||
| 2025-08-23 | 229,005 (+3,106) | 199,238 (+2,034) | 428,243 (+5,140) |
|
||||
| 2025-08-24 | 232,098 (+3,093) | 201,157 (+1,919) | 433,255 (+5,012) |
|
||||
| 2025-08-25 | 236,607 (+4,509) | 202,650 (+1,493) | 439,257 (+6,002) |
|
||||
| 2025-08-26 | 242,783 (+6,176) | 205,242 (+2,592) | 448,025 (+8,768) |
|
||||
| 2025-08-27 | 248,409 (+5,626) | 205,242 (+0) | 453,651 (+5,626) |
|
||||
| 2025-08-28 | 252,796 (+4,387) | 205,242 (+0) | 458,038 (+4,387) |
|
||||
| 2025-08-29 | 256,045 (+3,249) | 211,075 (+5,833) | 467,120 (+9,082) |
|
||||
| 2025-08-30 | 258,863 (+2,818) | 212,397 (+1,322) | 471,260 (+4,140) |
|
||||
| 2025-08-31 | 262,004 (+3,141) | 213,944 (+1,547) | 475,948 (+4,688) |
|
||||
| 2025-09-01 | 265,359 (+3,355) | 215,115 (+1,171) | 480,474 (+4,526) |
|
||||
| 2025-09-02 | 270,483 (+5,124) | 217,075 (+1,960) | 487,558 (+7,084) |
|
||||
| 2025-09-03 | 274,793 (+4,310) | 219,755 (+2,680) | 494,548 (+6,990) |
|
||||
| 2025-09-04 | 280,430 (+5,637) | 222,103 (+2,348) | 502,533 (+7,985) |
|
||||
| 2025-09-05 | 283,769 (+3,339) | 223,793 (+1,690) | 507,562 (+5,029) |
|
||||
| 2025-09-06 | 286,245 (+2,476) | 225,036 (+1,243) | 511,281 (+3,719) |
|
||||
| 2025-09-07 | 288,623 (+2,378) | 225,866 (+830) | 514,489 (+3,208) |
|
||||
| 2025-09-08 | 293,341 (+4,718) | 227,073 (+1,207) | 520,414 (+5,925) |
|
||||
| 2025-09-09 | 300,036 (+6,695) | 229,788 (+2,715) | 529,824 (+9,410) |
|
||||
| 2025-09-10 | 307,287 (+7,251) | 233,435 (+3,647) | 540,722 (+10,898) |
|
||||
| 2025-09-11 | 314,083 (+6,796) | 237,356 (+3,921) | 551,439 (+10,717) |
|
||||
| 2025-09-12 | 321,046 (+6,963) | 240,728 (+3,372) | 561,774 (+10,335) |
|
||||
| 2025-09-13 | 324,894 (+3,848) | 245,539 (+4,811) | 570,433 (+8,659) |
|
||||
| 2025-09-14 | 328,876 (+3,982) | 248,245 (+2,706) | 577,121 (+6,688) |
|
||||
| 2025-09-15 | 334,201 (+5,325) | 250,983 (+2,738) | 585,184 (+8,063) |
|
||||
| 2025-09-16 | 342,609 (+8,408) | 255,264 (+4,281) | 597,873 (+12,689) |
|
||||
| 2025-09-17 | 351,117 (+8,508) | 260,970 (+5,706) | 612,087 (+14,214) |
|
||||
| 2025-09-18 | 358,717 (+7,600) | 266,922 (+5,952) | 625,639 (+13,552) |
|
||||
| 2025-09-19 | 365,401 (+6,684) | 271,859 (+4,937) | 637,260 (+11,621) |
|
||||
| 2025-09-20 | 372,092 (+6,691) | 276,917 (+5,058) | 649,009 (+11,749) |
|
||||
| 2025-09-21 | 377,079 (+4,987) | 280,261 (+3,344) | 657,340 (+8,331) |
|
||||
| 2025-09-22 | 382,492 (+5,413) | 284,009 (+3,748) | 666,501 (+9,161) |
|
||||
| 2025-09-23 | 387,008 (+4,516) | 289,129 (+5,120) | 676,137 (+9,636) |
|
||||
| 2025-09-24 | 393,325 (+6,317) | 294,927 (+5,798) | 688,252 (+12,115) |
|
||||
| 2025-09-25 | 398,879 (+5,554) | 301,663 (+6,736) | 700,542 (+12,290) |
|
||||
| 2025-09-26 | 404,334 (+5,455) | 306,713 (+5,050) | 711,047 (+10,505) |
|
||||
| 2025-09-27 | 411,618 (+7,284) | 317,763 (+11,050) | 729,381 (+18,334) |
|
||||
| 2025-09-28 | 414,910 (+3,292) | 322,522 (+4,759) | 737,432 (+8,051) |
|
||||
| 2025-09-29 | 419,919 (+5,009) | 328,033 (+5,511) | 747,952 (+10,520) |
|
||||
| 2025-09-30 | 427,991 (+8,072) | 336,472 (+8,439) | 764,463 (+16,511) |
|
||||
| 2025-10-01 | 433,591 (+5,600) | 341,742 (+5,270) | 775,333 (+10,870) |
|
||||
| 2025-10-02 | 440,852 (+7,261) | 348,099 (+6,357) | 788,951 (+13,618) |
|
||||
| 2025-10-03 | 446,829 (+5,977) | 359,937 (+11,838) | 806,766 (+17,815) |
|
||||
| 2025-10-04 | 452,561 (+5,732) | 370,386 (+10,449) | 822,947 (+16,181) |
|
||||
| 2025-10-05 | 455,559 (+2,998) | 374,745 (+4,359) | 830,304 (+7,357) |
|
||||
| 2025-10-06 | 460,927 (+5,368) | 379,489 (+4,744) | 840,416 (+10,112) |
|
||||
| 2025-10-07 | 467,336 (+6,409) | 385,438 (+5,949) | 852,774 (+12,358) |
|
||||
| 2025-10-08 | 474,643 (+7,307) | 394,139 (+8,701) | 868,782 (+16,008) |
|
||||
| 2025-10-09 | 479,203 (+4,560) | 400,526 (+6,387) | 879,729 (+10,947) |
|
||||
| 2025-10-10 | 484,374 (+5,171) | 406,015 (+5,489) | 890,389 (+10,660) |
|
||||
| 2025-10-11 | 488,427 (+4,053) | 414,699 (+8,684) | 903,126 (+12,737) |
|
||||
| 2025-10-12 | 492,125 (+3,698) | 418,745 (+4,046) | 910,870 (+7,744) |
|
||||
| 2025-10-14 | 505,130 (+13,005) | 429,286 (+10,541) | 934,416 (+23,546) |
|
||||
| 2025-10-15 | 512,717 (+7,587) | 439,290 (+10,004) | 952,007 (+17,591) |
|
||||
| 2025-10-16 | 517,719 (+5,002) | 447,137 (+7,847) | 964,856 (+12,849) |
|
||||
| 2025-10-17 | 526,239 (+8,520) | 457,467 (+10,330) | 983,706 (+18,850) |
|
||||
| 2025-10-18 | 531,564 (+5,325) | 465,272 (+7,805) | 996,836 (+13,130) |
|
||||
| 2025-10-19 | 536,209 (+4,645) | 469,078 (+3,806) | 1,005,287 (+8,451) |
|
||||
| 2025-10-20 | 541,264 (+5,055) | 472,952 (+3,874) | 1,014,216 (+8,929) |
|
||||
| 2025-10-21 | 548,721 (+7,457) | 479,703 (+6,751) | 1,028,424 (+14,208) |
|
||||
| 2025-10-22 | 557,949 (+9,228) | 491,395 (+11,692) | 1,049,344 (+20,920) |
|
||||
| 2025-10-23 | 564,716 (+6,767) | 498,736 (+7,341) | 1,063,452 (+14,108) |
|
||||
| 2025-10-24 | 572,692 (+7,976) | 506,905 (+8,169) | 1,079,597 (+16,145) |
|
||||
| 2025-10-25 | 578,927 (+6,235) | 516,129 (+9,224) | 1,095,056 (+15,459) |
|
||||
| 2025-10-26 | 584,409 (+5,482) | 521,179 (+5,050) | 1,105,588 (+10,532) |
|
||||
| 2025-10-27 | 589,999 (+5,590) | 526,001 (+4,822) | 1,116,000 (+10,412) |
|
||||
| 2025-10-28 | 595,776 (+5,777) | 532,438 (+6,437) | 1,128,214 (+12,214) |
|
||||
| 2025-10-29 | 606,259 (+10,483) | 542,064 (+9,626) | 1,148,323 (+20,109) |
|
||||
| 2025-10-30 | 613,746 (+7,487) | 542,064 (+0) | 1,155,810 (+7,487) |
|
||||
| 2025-10-30 | 617,846 (+4,100) | 555,026 (+12,962) | 1,172,872 (+17,062) |
|
||||
| 2025-10-31 | 626,612 (+8,766) | 564,579 (+9,553) | 1,191,191 (+18,319) |
|
||||
| 2025-11-01 | 636,100 (+9,488) | 581,806 (+17,227) | 1,217,906 (+26,715) |
|
||||
| 2025-11-02 | 644,067 (+7,967) | 590,004 (+8,198) | 1,234,071 (+16,165) |
|
||||
| 2025-11-03 | 653,130 (+9,063) | 597,139 (+7,135) | 1,250,269 (+16,198) |
|
||||
| 2025-11-04 | 663,912 (+10,782) | 608,056 (+10,917) | 1,271,968 (+21,699) |
|
||||
| 2025-11-05 | 675,074 (+11,162) | 619,690 (+11,634) | 1,294,764 (+22,796) |
|
||||
| 2025-11-06 | 686,252 (+11,178) | 630,885 (+11,195) | 1,317,137 (+22,373) |
|
||||
| 2025-11-07 | 696,646 (+10,394) | 642,146 (+11,261) | 1,338,792 (+21,655) |
|
||||
| 2025-11-08 | 706,035 (+9,389) | 653,489 (+11,343) | 1,359,524 (+20,732) |
|
||||
| 2025-11-09 | 713,462 (+7,427) | 660,459 (+6,970) | 1,373,921 (+14,397) |
|
||||
| 2025-11-10 | 722,288 (+8,826) | 668,225 (+7,766) | 1,390,513 (+16,592) |
|
||||
| 2025-11-11 | 729,769 (+7,481) | 677,501 (+9,276) | 1,407,270 (+16,757) |
|
||||
| 2025-11-12 | 740,180 (+10,411) | 686,454 (+8,953) | 1,426,634 (+19,364) |
|
||||
| 2025-11-13 | 749,905 (+9,725) | 696,157 (+9,703) | 1,446,062 (+19,428) |
|
||||
| 2025-11-14 | 759,928 (+10,023) | 705,237 (+9,080) | 1,465,165 (+19,103) |
|
||||
| 2025-11-15 | 765,955 (+6,027) | 712,870 (+7,633) | 1,478,825 (+13,660) |
|
||||
| 2025-11-16 | 771,069 (+5,114) | 716,596 (+3,726) | 1,487,665 (+8,840) |
|
||||
| 2025-11-17 | 780,161 (+9,092) | 723,339 (+6,743) | 1,503,500 (+15,835) |
|
||||
| 2025-11-18 | 791,563 (+11,402) | 732,544 (+9,205) | 1,524,107 (+20,607) |
|
||||
| 2025-11-19 | 804,409 (+12,846) | 747,624 (+15,080) | 1,552,033 (+27,926) |
|
||||
| 2025-11-20 | 814,620 (+10,211) | 757,907 (+10,283) | 1,572,527 (+20,494) |
|
||||
| 2025-11-21 | 826,309 (+11,689) | 769,307 (+11,400) | 1,595,616 (+23,089) |
|
||||
| 2025-11-22 | 837,269 (+10,960) | 780,996 (+11,689) | 1,618,265 (+22,649) |
|
||||
| 2025-11-23 | 846,609 (+9,340) | 795,069 (+14,073) | 1,641,678 (+23,413) |
|
||||
| 2025-11-24 | 856,733 (+10,124) | 804,033 (+8,964) | 1,660,766 (+19,088) |
|
||||
| 2025-11-25 | 869,423 (+12,690) | 817,339 (+13,306) | 1,686,762 (+25,996) |
|
||||
| 2025-11-26 | 881,414 (+11,991) | 832,518 (+15,179) | 1,713,932 (+27,170) |
|
||||
| 2025-11-27 | 893,960 (+12,546) | 846,180 (+13,662) | 1,740,140 (+26,208) |
|
||||
| 2025-11-28 | 901,741 (+7,781) | 856,482 (+10,302) | 1,758,223 (+18,083) |
|
||||
| 2025-11-29 | 908,689 (+6,948) | 863,361 (+6,879) | 1,772,050 (+13,827) |
|
||||
| 2025-11-30 | 916,116 (+7,427) | 870,194 (+6,833) | 1,786,310 (+14,260) |
|
||||
| 2025-12-01 | 925,898 (+9,782) | 876,500 (+6,306) | 1,802,398 (+16,088) |
|
||||
| 2025-12-02 | 939,250 (+13,352) | 890,919 (+14,419) | 1,830,169 (+27,771) |
|
||||
| 2025-12-03 | 952,249 (+12,999) | 903,713 (+12,794) | 1,855,962 (+25,793) |
|
||||
| 2025-12-04 | 965,611 (+13,362) | 916,471 (+12,758) | 1,882,082 (+26,120) |
|
||||
| 2025-12-05 | 977,996 (+12,385) | 930,616 (+14,145) | 1,908,612 (+26,530) |
|
||||
| 2025-12-06 | 987,884 (+9,888) | 943,773 (+13,157) | 1,931,657 (+23,045) |
|
||||
| Date | GitHub Downloads | npm Downloads | Total |
|
||||
| ---------- | ------------------ | ----------------- | ------------------- |
|
||||
| 2025-06-29 | 18,789 (+0) | 39,420 (+0) | 58,209 (+0) |
|
||||
| 2025-06-30 | 20,127 (+1,338) | 41,059 (+1,639) | 61,186 (+2,977) |
|
||||
| 2025-07-01 | 22,108 (+1,981) | 43,745 (+2,686) | 65,853 (+4,667) |
|
||||
| 2025-07-02 | 24,814 (+2,706) | 46,168 (+2,423) | 70,982 (+5,129) |
|
||||
| 2025-07-03 | 27,834 (+3,020) | 49,955 (+3,787) | 77,789 (+6,807) |
|
||||
| 2025-07-04 | 30,608 (+2,774) | 54,758 (+4,803) | 85,366 (+7,577) |
|
||||
| 2025-07-05 | 32,524 (+1,916) | 58,371 (+3,613) | 90,895 (+5,529) |
|
||||
| 2025-07-06 | 33,766 (+1,242) | 59,694 (+1,323) | 93,460 (+2,565) |
|
||||
| 2025-07-08 | 38,052 (+4,286) | 64,468 (+4,774) | 102,520 (+9,060) |
|
||||
| 2025-07-09 | 40,924 (+2,872) | 67,935 (+3,467) | 108,859 (+6,339) |
|
||||
| 2025-07-10 | 43,796 (+2,872) | 71,402 (+3,467) | 115,198 (+6,339) |
|
||||
| 2025-07-11 | 46,982 (+3,186) | 77,462 (+6,060) | 124,444 (+9,246) |
|
||||
| 2025-07-12 | 49,302 (+2,320) | 82,177 (+4,715) | 131,479 (+7,035) |
|
||||
| 2025-07-13 | 50,803 (+1,501) | 86,394 (+4,217) | 137,197 (+5,718) |
|
||||
| 2025-07-14 | 53,283 (+2,480) | 87,860 (+1,466) | 141,143 (+3,946) |
|
||||
| 2025-07-15 | 57,590 (+4,307) | 91,036 (+3,176) | 148,626 (+7,483) |
|
||||
| 2025-07-16 | 62,313 (+4,723) | 95,258 (+4,222) | 157,571 (+8,945) |
|
||||
| 2025-07-17 | 66,684 (+4,371) | 100,048 (+4,790) | 166,732 (+9,161) |
|
||||
| 2025-07-18 | 70,379 (+3,695) | 102,587 (+2,539) | 172,966 (+6,234) |
|
||||
| 2025-07-19 | 73,497 (+3,117) | 105,904 (+3,317) | 179,401 (+6,434) |
|
||||
| 2025-07-20 | 76,453 (+2,956) | 109,044 (+3,140) | 185,497 (+6,096) |
|
||||
| 2025-07-21 | 80,197 (+3,744) | 113,537 (+4,493) | 193,734 (+8,237) |
|
||||
| 2025-07-22 | 84,251 (+4,054) | 118,073 (+4,536) | 202,324 (+8,590) |
|
||||
| 2025-07-23 | 88,589 (+4,338) | 121,436 (+3,363) | 210,025 (+7,701) |
|
||||
| 2025-07-24 | 92,469 (+3,880) | 124,091 (+2,655) | 216,560 (+6,535) |
|
||||
| 2025-07-25 | 96,417 (+3,948) | 126,985 (+2,894) | 223,402 (+6,842) |
|
||||
| 2025-07-26 | 100,646 (+4,229) | 131,411 (+4,426) | 232,057 (+8,655) |
|
||||
| 2025-07-27 | 102,644 (+1,998) | 134,736 (+3,325) | 237,380 (+5,323) |
|
||||
| 2025-07-28 | 105,446 (+2,802) | 136,016 (+1,280) | 241,462 (+4,082) |
|
||||
| 2025-07-29 | 108,998 (+3,552) | 137,542 (+1,526) | 246,540 (+5,078) |
|
||||
| 2025-07-30 | 113,544 (+4,546) | 140,317 (+2,775) | 253,861 (+7,321) |
|
||||
| 2025-07-31 | 118,339 (+4,795) | 143,344 (+3,027) | 261,683 (+7,822) |
|
||||
| 2025-08-01 | 123,539 (+5,200) | 146,680 (+3,336) | 270,219 (+8,536) |
|
||||
| 2025-08-02 | 127,864 (+4,325) | 149,236 (+2,556) | 277,100 (+6,881) |
|
||||
| 2025-08-03 | 131,397 (+3,533) | 150,451 (+1,215) | 281,848 (+4,748) |
|
||||
| 2025-08-04 | 136,266 (+4,869) | 153,260 (+2,809) | 289,526 (+7,678) |
|
||||
| 2025-08-05 | 141,596 (+5,330) | 155,752 (+2,492) | 297,348 (+7,822) |
|
||||
| 2025-08-06 | 147,067 (+5,471) | 158,309 (+2,557) | 305,376 (+8,028) |
|
||||
| 2025-08-07 | 152,591 (+5,524) | 160,889 (+2,580) | 313,480 (+8,104) |
|
||||
| 2025-08-08 | 158,187 (+5,596) | 163,448 (+2,559) | 321,635 (+8,155) |
|
||||
| 2025-08-09 | 162,770 (+4,583) | 165,721 (+2,273) | 328,491 (+6,856) |
|
||||
| 2025-08-10 | 165,695 (+2,925) | 167,109 (+1,388) | 332,804 (+4,313) |
|
||||
| 2025-08-11 | 169,297 (+3,602) | 167,953 (+844) | 337,250 (+4,446) |
|
||||
| 2025-08-12 | 176,307 (+7,010) | 171,876 (+3,923) | 348,183 (+10,933) |
|
||||
| 2025-08-13 | 182,997 (+6,690) | 177,182 (+5,306) | 360,179 (+11,996) |
|
||||
| 2025-08-14 | 189,063 (+6,066) | 179,741 (+2,559) | 368,804 (+8,625) |
|
||||
| 2025-08-15 | 193,608 (+4,545) | 181,792 (+2,051) | 375,400 (+6,596) |
|
||||
| 2025-08-16 | 198,118 (+4,510) | 184,558 (+2,766) | 382,676 (+7,276) |
|
||||
| 2025-08-17 | 201,299 (+3,181) | 186,269 (+1,711) | 387,568 (+4,892) |
|
||||
| 2025-08-18 | 204,559 (+3,260) | 187,399 (+1,130) | 391,958 (+4,390) |
|
||||
| 2025-08-19 | 209,814 (+5,255) | 189,668 (+2,269) | 399,482 (+7,524) |
|
||||
| 2025-08-20 | 214,497 (+4,683) | 191,481 (+1,813) | 405,978 (+6,496) |
|
||||
| 2025-08-21 | 220,465 (+5,968) | 194,784 (+3,303) | 415,249 (+9,271) |
|
||||
| 2025-08-22 | 225,899 (+5,434) | 197,204 (+2,420) | 423,103 (+7,854) |
|
||||
| 2025-08-23 | 229,005 (+3,106) | 199,238 (+2,034) | 428,243 (+5,140) |
|
||||
| 2025-08-24 | 232,098 (+3,093) | 201,157 (+1,919) | 433,255 (+5,012) |
|
||||
| 2025-08-25 | 236,607 (+4,509) | 202,650 (+1,493) | 439,257 (+6,002) |
|
||||
| 2025-08-26 | 242,783 (+6,176) | 205,242 (+2,592) | 448,025 (+8,768) |
|
||||
| 2025-08-27 | 248,409 (+5,626) | 205,242 (+0) | 453,651 (+5,626) |
|
||||
| 2025-08-28 | 252,796 (+4,387) | 205,242 (+0) | 458,038 (+4,387) |
|
||||
| 2025-08-29 | 256,045 (+3,249) | 211,075 (+5,833) | 467,120 (+9,082) |
|
||||
| 2025-08-30 | 258,863 (+2,818) | 212,397 (+1,322) | 471,260 (+4,140) |
|
||||
| 2025-08-31 | 262,004 (+3,141) | 213,944 (+1,547) | 475,948 (+4,688) |
|
||||
| 2025-09-01 | 265,359 (+3,355) | 215,115 (+1,171) | 480,474 (+4,526) |
|
||||
| 2025-09-02 | 270,483 (+5,124) | 217,075 (+1,960) | 487,558 (+7,084) |
|
||||
| 2025-09-03 | 274,793 (+4,310) | 219,755 (+2,680) | 494,548 (+6,990) |
|
||||
| 2025-09-04 | 280,430 (+5,637) | 222,103 (+2,348) | 502,533 (+7,985) |
|
||||
| 2025-09-05 | 283,769 (+3,339) | 223,793 (+1,690) | 507,562 (+5,029) |
|
||||
| 2025-09-06 | 286,245 (+2,476) | 225,036 (+1,243) | 511,281 (+3,719) |
|
||||
| 2025-09-07 | 288,623 (+2,378) | 225,866 (+830) | 514,489 (+3,208) |
|
||||
| 2025-09-08 | 293,341 (+4,718) | 227,073 (+1,207) | 520,414 (+5,925) |
|
||||
| 2025-09-09 | 300,036 (+6,695) | 229,788 (+2,715) | 529,824 (+9,410) |
|
||||
| 2025-09-10 | 307,287 (+7,251) | 233,435 (+3,647) | 540,722 (+10,898) |
|
||||
| 2025-09-11 | 314,083 (+6,796) | 237,356 (+3,921) | 551,439 (+10,717) |
|
||||
| 2025-09-12 | 321,046 (+6,963) | 240,728 (+3,372) | 561,774 (+10,335) |
|
||||
| 2025-09-13 | 324,894 (+3,848) | 245,539 (+4,811) | 570,433 (+8,659) |
|
||||
| 2025-09-14 | 328,876 (+3,982) | 248,245 (+2,706) | 577,121 (+6,688) |
|
||||
| 2025-09-15 | 334,201 (+5,325) | 250,983 (+2,738) | 585,184 (+8,063) |
|
||||
| 2025-09-16 | 342,609 (+8,408) | 255,264 (+4,281) | 597,873 (+12,689) |
|
||||
| 2025-09-17 | 351,117 (+8,508) | 260,970 (+5,706) | 612,087 (+14,214) |
|
||||
| 2025-09-18 | 358,717 (+7,600) | 266,922 (+5,952) | 625,639 (+13,552) |
|
||||
| 2025-09-19 | 365,401 (+6,684) | 271,859 (+4,937) | 637,260 (+11,621) |
|
||||
| 2025-09-20 | 372,092 (+6,691) | 276,917 (+5,058) | 649,009 (+11,749) |
|
||||
| 2025-09-21 | 377,079 (+4,987) | 280,261 (+3,344) | 657,340 (+8,331) |
|
||||
| 2025-09-22 | 382,492 (+5,413) | 284,009 (+3,748) | 666,501 (+9,161) |
|
||||
| 2025-09-23 | 387,008 (+4,516) | 289,129 (+5,120) | 676,137 (+9,636) |
|
||||
| 2025-09-24 | 393,325 (+6,317) | 294,927 (+5,798) | 688,252 (+12,115) |
|
||||
| 2025-09-25 | 398,879 (+5,554) | 301,663 (+6,736) | 700,542 (+12,290) |
|
||||
| 2025-09-26 | 404,334 (+5,455) | 306,713 (+5,050) | 711,047 (+10,505) |
|
||||
| 2025-09-27 | 411,618 (+7,284) | 317,763 (+11,050) | 729,381 (+18,334) |
|
||||
| 2025-09-28 | 414,910 (+3,292) | 322,522 (+4,759) | 737,432 (+8,051) |
|
||||
| 2025-09-29 | 419,919 (+5,009) | 328,033 (+5,511) | 747,952 (+10,520) |
|
||||
| 2025-09-30 | 427,991 (+8,072) | 336,472 (+8,439) | 764,463 (+16,511) |
|
||||
| 2025-10-01 | 433,591 (+5,600) | 341,742 (+5,270) | 775,333 (+10,870) |
|
||||
| 2025-10-02 | 440,852 (+7,261) | 348,099 (+6,357) | 788,951 (+13,618) |
|
||||
| 2025-10-03 | 446,829 (+5,977) | 359,937 (+11,838) | 806,766 (+17,815) |
|
||||
| 2025-10-04 | 452,561 (+5,732) | 370,386 (+10,449) | 822,947 (+16,181) |
|
||||
| 2025-10-05 | 455,559 (+2,998) | 374,745 (+4,359) | 830,304 (+7,357) |
|
||||
| 2025-10-06 | 460,927 (+5,368) | 379,489 (+4,744) | 840,416 (+10,112) |
|
||||
| 2025-10-07 | 467,336 (+6,409) | 385,438 (+5,949) | 852,774 (+12,358) |
|
||||
| 2025-10-08 | 474,643 (+7,307) | 394,139 (+8,701) | 868,782 (+16,008) |
|
||||
| 2025-10-09 | 479,203 (+4,560) | 400,526 (+6,387) | 879,729 (+10,947) |
|
||||
| 2025-10-10 | 484,374 (+5,171) | 406,015 (+5,489) | 890,389 (+10,660) |
|
||||
| 2025-10-11 | 488,427 (+4,053) | 414,699 (+8,684) | 903,126 (+12,737) |
|
||||
| 2025-10-12 | 492,125 (+3,698) | 418,745 (+4,046) | 910,870 (+7,744) |
|
||||
| 2025-10-14 | 505,130 (+13,005) | 429,286 (+10,541) | 934,416 (+23,546) |
|
||||
| 2025-10-15 | 512,717 (+7,587) | 439,290 (+10,004) | 952,007 (+17,591) |
|
||||
| 2025-10-16 | 517,719 (+5,002) | 447,137 (+7,847) | 964,856 (+12,849) |
|
||||
| 2025-10-17 | 526,239 (+8,520) | 457,467 (+10,330) | 983,706 (+18,850) |
|
||||
| 2025-10-18 | 531,564 (+5,325) | 465,272 (+7,805) | 996,836 (+13,130) |
|
||||
| 2025-10-19 | 536,209 (+4,645) | 469,078 (+3,806) | 1,005,287 (+8,451) |
|
||||
| 2025-10-20 | 541,264 (+5,055) | 472,952 (+3,874) | 1,014,216 (+8,929) |
|
||||
| 2025-10-21 | 548,721 (+7,457) | 479,703 (+6,751) | 1,028,424 (+14,208) |
|
||||
| 2025-10-22 | 557,949 (+9,228) | 491,395 (+11,692) | 1,049,344 (+20,920) |
|
||||
| 2025-10-23 | 564,716 (+6,767) | 498,736 (+7,341) | 1,063,452 (+14,108) |
|
||||
| 2025-10-24 | 572,692 (+7,976) | 506,905 (+8,169) | 1,079,597 (+16,145) |
|
||||
| 2025-10-25 | 578,927 (+6,235) | 516,129 (+9,224) | 1,095,056 (+15,459) |
|
||||
| 2025-10-26 | 584,409 (+5,482) | 521,179 (+5,050) | 1,105,588 (+10,532) |
|
||||
| 2025-10-27 | 589,999 (+5,590) | 526,001 (+4,822) | 1,116,000 (+10,412) |
|
||||
| 2025-10-28 | 595,776 (+5,777) | 532,438 (+6,437) | 1,128,214 (+12,214) |
|
||||
| 2025-10-29 | 606,259 (+10,483) | 542,064 (+9,626) | 1,148,323 (+20,109) |
|
||||
| 2025-10-30 | 613,746 (+7,487) | 542,064 (+0) | 1,155,810 (+7,487) |
|
||||
| 2025-10-30 | 617,846 (+4,100) | 555,026 (+12,962) | 1,172,872 (+17,062) |
|
||||
| 2025-10-31 | 626,612 (+8,766) | 564,579 (+9,553) | 1,191,191 (+18,319) |
|
||||
| 2025-11-01 | 636,100 (+9,488) | 581,806 (+17,227) | 1,217,906 (+26,715) |
|
||||
| 2025-11-02 | 644,067 (+7,967) | 590,004 (+8,198) | 1,234,071 (+16,165) |
|
||||
| 2025-11-03 | 653,130 (+9,063) | 597,139 (+7,135) | 1,250,269 (+16,198) |
|
||||
| 2025-11-04 | 663,912 (+10,782) | 608,056 (+10,917) | 1,271,968 (+21,699) |
|
||||
| 2025-11-05 | 675,074 (+11,162) | 619,690 (+11,634) | 1,294,764 (+22,796) |
|
||||
| 2025-11-06 | 686,252 (+11,178) | 630,885 (+11,195) | 1,317,137 (+22,373) |
|
||||
| 2025-11-07 | 696,646 (+10,394) | 642,146 (+11,261) | 1,338,792 (+21,655) |
|
||||
| 2025-11-08 | 706,035 (+9,389) | 653,489 (+11,343) | 1,359,524 (+20,732) |
|
||||
| 2025-11-09 | 713,462 (+7,427) | 660,459 (+6,970) | 1,373,921 (+14,397) |
|
||||
| 2025-11-10 | 722,288 (+8,826) | 668,225 (+7,766) | 1,390,513 (+16,592) |
|
||||
| 2025-11-11 | 729,769 (+7,481) | 677,501 (+9,276) | 1,407,270 (+16,757) |
|
||||
| 2025-11-12 | 740,180 (+10,411) | 686,454 (+8,953) | 1,426,634 (+19,364) |
|
||||
| 2025-11-13 | 749,905 (+9,725) | 696,157 (+9,703) | 1,446,062 (+19,428) |
|
||||
| 2025-11-14 | 759,928 (+10,023) | 705,237 (+9,080) | 1,465,165 (+19,103) |
|
||||
| 2025-11-15 | 765,955 (+6,027) | 712,870 (+7,633) | 1,478,825 (+13,660) |
|
||||
| 2025-11-16 | 771,069 (+5,114) | 716,596 (+3,726) | 1,487,665 (+8,840) |
|
||||
| 2025-11-17 | 780,161 (+9,092) | 723,339 (+6,743) | 1,503,500 (+15,835) |
|
||||
| 2025-11-18 | 791,563 (+11,402) | 732,544 (+9,205) | 1,524,107 (+20,607) |
|
||||
| 2025-11-19 | 804,409 (+12,846) | 747,624 (+15,080) | 1,552,033 (+27,926) |
|
||||
| 2025-11-20 | 814,620 (+10,211) | 757,907 (+10,283) | 1,572,527 (+20,494) |
|
||||
| 2025-11-21 | 826,309 (+11,689) | 769,307 (+11,400) | 1,595,616 (+23,089) |
|
||||
| 2025-11-22 | 837,269 (+10,960) | 780,996 (+11,689) | 1,618,265 (+22,649) |
|
||||
| 2025-11-23 | 846,609 (+9,340) | 795,069 (+14,073) | 1,641,678 (+23,413) |
|
||||
| 2025-11-24 | 856,733 (+10,124) | 804,033 (+8,964) | 1,660,766 (+19,088) |
|
||||
| 2025-11-25 | 869,423 (+12,690) | 817,339 (+13,306) | 1,686,762 (+25,996) |
|
||||
| 2025-11-26 | 881,414 (+11,991) | 832,518 (+15,179) | 1,713,932 (+27,170) |
|
||||
| 2025-11-27 | 893,960 (+12,546) | 846,180 (+13,662) | 1,740,140 (+26,208) |
|
||||
| 2025-11-28 | 901,741 (+7,781) | 856,482 (+10,302) | 1,758,223 (+18,083) |
|
||||
| 2025-11-29 | 908,689 (+6,948) | 863,361 (+6,879) | 1,772,050 (+13,827) |
|
||||
| 2025-11-30 | 916,116 (+7,427) | 870,194 (+6,833) | 1,786,310 (+14,260) |
|
||||
| 2025-12-01 | 925,898 (+9,782) | 876,500 (+6,306) | 1,802,398 (+16,088) |
|
||||
| 2025-12-02 | 939,250 (+13,352) | 890,919 (+14,419) | 1,830,169 (+27,771) |
|
||||
| 2025-12-03 | 952,249 (+12,999) | 903,713 (+12,794) | 1,855,962 (+25,793) |
|
||||
| 2025-12-04 | 965,611 (+13,362) | 916,471 (+12,758) | 1,882,082 (+26,120) |
|
||||
| 2025-12-05 | 977,996 (+12,385) | 930,616 (+14,145) | 1,908,612 (+26,530) |
|
||||
| 2025-12-06 | 987,884 (+9,888) | 943,773 (+13,157) | 1,931,657 (+23,045) |
|
||||
| 2025-12-07 | 994,046 (+6,162) | 951,425 (+7,652) | 1,945,471 (+13,814) |
|
||||
| 2025-12-08 | 1,000,898 (+6,852) | 957,149 (+5,724) | 1,958,047 (+12,576) |
|
||||
|
||||
158
bun.lock
@@ -20,7 +20,7 @@
|
||||
},
|
||||
"packages/console/app": {
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"dependencies": {
|
||||
"@cloudflare/vite-plugin": "1.15.2",
|
||||
"@ibm/plex": "6.4.1",
|
||||
@@ -48,7 +48,7 @@
|
||||
},
|
||||
"packages/console/core": {
|
||||
"name": "@opencode-ai/console-core",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-sts": "3.782.0",
|
||||
"@jsx-email/render": "1.1.1",
|
||||
@@ -75,7 +75,7 @@
|
||||
},
|
||||
"packages/console/function": {
|
||||
"name": "@opencode-ai/console-function",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "2.0.0",
|
||||
"@ai-sdk/openai": "2.0.2",
|
||||
@@ -99,7 +99,7 @@
|
||||
},
|
||||
"packages/console/mail": {
|
||||
"name": "@opencode-ai/console-mail",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"dependencies": {
|
||||
"@jsx-email/all": "2.2.3",
|
||||
"@jsx-email/cli": "1.4.3",
|
||||
@@ -123,7 +123,7 @@
|
||||
},
|
||||
"packages/desktop": {
|
||||
"name": "@opencode-ai/desktop",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
@@ -168,7 +168,7 @@
|
||||
},
|
||||
"packages/enterprise": {
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"dependencies": {
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
"@opencode-ai/util": "workspace:*",
|
||||
@@ -196,7 +196,7 @@
|
||||
},
|
||||
"packages/function": {
|
||||
"name": "@opencode-ai/function",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"dependencies": {
|
||||
"@octokit/auth-app": "8.0.1",
|
||||
"@octokit/rest": "22.0.0",
|
||||
@@ -212,7 +212,7 @@
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "opencode",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -242,8 +242,8 @@
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@opencode-ai/util": "workspace:*",
|
||||
"@openrouter/ai-sdk-provider": "1.2.8",
|
||||
"@opentui/core": "0.1.56",
|
||||
"@opentui/solid": "0.1.56",
|
||||
"@opentui/core": "0.1.59",
|
||||
"@opentui/solid": "0.1.59",
|
||||
"@parcel/watcher": "2.5.1",
|
||||
"@pierre/precision-diffs": "catalog:",
|
||||
"@solid-primitives/event-bus": "1.1.2",
|
||||
@@ -285,7 +285,9 @@
|
||||
"@parcel/watcher-darwin-arm64": "2.5.1",
|
||||
"@parcel/watcher-darwin-x64": "2.5.1",
|
||||
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-arm64-musl": "2.5.1",
|
||||
"@parcel/watcher-linux-x64-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-x64-musl": "2.5.1",
|
||||
"@parcel/watcher-win32-x64": "2.5.1",
|
||||
"@standard-schema/spec": "1.0.0",
|
||||
"@tsconfig/bun": "catalog:",
|
||||
@@ -302,7 +304,7 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"zod": "catalog:",
|
||||
@@ -322,9 +324,9 @@
|
||||
},
|
||||
"packages/sdk/js": {
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "0.81.0",
|
||||
"@hey-api/openapi-ts": "0.88.1",
|
||||
"@tsconfig/node22": "catalog:",
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
@@ -333,7 +335,7 @@
|
||||
},
|
||||
"packages/slack": {
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@slack/bolt": "^3.17.1",
|
||||
@@ -346,7 +348,7 @@
|
||||
},
|
||||
"packages/tauri": {
|
||||
"name": "@opencode-ai/tauri",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"dependencies": {
|
||||
"@opencode-ai/desktop": "workspace:*",
|
||||
"@tauri-apps/api": "^2",
|
||||
@@ -366,7 +368,7 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
@@ -398,7 +400,7 @@
|
||||
},
|
||||
"packages/util": {
|
||||
"name": "@opencode-ai/util",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"dependencies": {
|
||||
"zod": "catalog:",
|
||||
},
|
||||
@@ -409,7 +411,7 @@
|
||||
},
|
||||
"packages/web": {
|
||||
"name": "@opencode-ai/web",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "12.6.3",
|
||||
"@astrojs/markdown-remark": "6.3.1",
|
||||
@@ -458,7 +460,7 @@
|
||||
"@hono/zod-validator": "0.4.2",
|
||||
"@kobalte/core": "0.13.11",
|
||||
"@openauthjs/openauth": "0.0.0-20250322224806",
|
||||
"@pierre/precision-diffs": "0.6.0-beta.3",
|
||||
"@pierre/precision-diffs": "0.6.0-beta.10",
|
||||
"@solidjs/meta": "0.29.4",
|
||||
"@solidjs/router": "0.15.4",
|
||||
"@solidjs/start": "https://pkg.pr.new/@solidjs/start@dfb2020",
|
||||
@@ -468,12 +470,12 @@
|
||||
"@types/bun": "1.3.3",
|
||||
"@types/luxon": "3.7.1",
|
||||
"@types/node": "22.13.9",
|
||||
"@typescript/native-preview": "7.0.0-dev.20251014.1",
|
||||
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|
||||
"ai": "5.0.97",
|
||||
"diff": "8.0.2",
|
||||
"fuzzysort": "3.1.0",
|
||||
"hono": "4.10.7",
|
||||
"hono-openapi": "1.1.1",
|
||||
"hono-openapi": "1.1.2",
|
||||
"luxon": "3.6.1",
|
||||
"remeda": "2.26.0",
|
||||
"solid-js": "1.9.10",
|
||||
@@ -851,9 +853,11 @@
|
||||
|
||||
"@happy-dom/global-registrator": ["@happy-dom/global-registrator@20.0.11", "", { "dependencies": { "@types/node": "^20.0.0", "happy-dom": "^20.0.11" } }, "sha512-GqNqiShBT/lzkHTMC/slKBrvN0DsD4Di8ssBk4aDaVgEn+2WMzE6DXxq701ndSXj7/0cJ8mNT71pM7Bnrr6JRw=="],
|
||||
|
||||
"@hey-api/json-schema-ref-parser": ["@hey-api/json-schema-ref-parser@1.0.6", "", { "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.0", "lodash": "^4.17.21" } }, "sha512-yktiFZoWPtEW8QKS65eqKwA5MTKp88CyiL8q72WynrBs/73SAaxlSWlA2zW/DZlywZ5hX1OYzrCC0wFdvO9c2w=="],
|
||||
"@hey-api/codegen-core": ["@hey-api/codegen-core@0.3.3", "", { "peerDependencies": { "typescript": ">=5.5.3" } }, "sha512-vArVDtrvdzFewu1hnjUm4jX1NBITlSCeO81EdWq676MxQbyxsGcDPAgohaSA+Wvr4HjPSvsg2/1s2zYxUtXebg=="],
|
||||
|
||||
"@hey-api/openapi-ts": ["@hey-api/openapi-ts@0.81.0", "", { "dependencies": { "@hey-api/json-schema-ref-parser": "1.0.6", "ansi-colors": "4.1.3", "c12": "2.0.1", "color-support": "1.1.3", "commander": "13.0.0", "handlebars": "4.7.8", "js-yaml": "4.1.0", "open": "10.1.2", "semver": "7.7.2" }, "peerDependencies": { "typescript": "^5.5.3" }, "bin": { "openapi-ts": "bin/index.cjs" } }, "sha512-PoJukNBkUfHOoMDpN33bBETX49TUhy7Hu8Sa0jslOvFndvZ5VjQr4Nl/Dzjb9LG1Lp5HjybyTJMA6a1zYk/q6A=="],
|
||||
"@hey-api/json-schema-ref-parser": ["@hey-api/json-schema-ref-parser@1.2.2", "", { "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.1", "lodash": "^4.17.21" } }, "sha512-oS+5yAdwnK20lSeFO1d53Ku+yaGCsY8PcrmSq2GtSs3bsBfRnHAbpPKSVzQcaxAOrzj5NB+f34WhZglVrNayBA=="],
|
||||
|
||||
"@hey-api/openapi-ts": ["@hey-api/openapi-ts@0.88.1", "", { "dependencies": { "@hey-api/codegen-core": "^0.3.3", "@hey-api/json-schema-ref-parser": "1.2.2", "ansi-colors": "4.1.3", "c12": "3.3.2", "color-support": "1.1.3", "commander": "14.0.2", "open": "11.0.0", "semver": "7.7.2" }, "peerDependencies": { "typescript": ">=5.5.3" }, "bin": { "openapi-ts": "bin/run.js" } }, "sha512-x/nDTupOnV9VuSeNIiJpgIpc915GHduhyseJeMTnI0JMsXaObmpa0rgPr3ASVEYMLgpvqozIEG1RTOOnal6zLQ=="],
|
||||
|
||||
"@hono/standard-validator": ["@hono/standard-validator@0.1.5", "", { "peerDependencies": { "@standard-schema/spec": "1.0.0", "hono": ">=3.9.0" } }, "sha512-EIyZPPwkyLn6XKwFj5NBEWHXhXbgmnVh2ceIFo5GO7gKI9WmzTjPDKnppQB0KrqKeAkq3kpoW4SIbu5X1dgx3w=="],
|
||||
|
||||
@@ -1141,21 +1145,21 @@
|
||||
|
||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
||||
|
||||
"@opentui/core": ["@opentui/core@0.1.56", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.56", "@opentui/core-darwin-x64": "0.1.56", "@opentui/core-linux-arm64": "0.1.56", "@opentui/core-linux-x64": "0.1.56", "@opentui/core-win32-arm64": "0.1.56", "@opentui/core-win32-x64": "0.1.56", "bun-webgpu": "0.1.4", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-TI5cSCPYythHIQYpAEdXyZhewGACn2TfnfC1qZmrSyEq33zFo4W7zpQ4EZNpy9xZJFCI+elAUVJFARwhudp9EQ=="],
|
||||
"@opentui/core": ["@opentui/core@0.1.59", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.59", "@opentui/core-darwin-x64": "0.1.59", "@opentui/core-linux-arm64": "0.1.59", "@opentui/core-linux-x64": "0.1.59", "@opentui/core-win32-arm64": "0.1.59", "@opentui/core-win32-x64": "0.1.59", "bun-webgpu": "0.1.4", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-vOtEvIulvfCOWJy0EfKAPzAMtDTmC+S0boGYrefjLqIp7tp+bbVJuXVh/8bz6GQTPmbQC6MIk6bv/ij3pdUVkA=="],
|
||||
|
||||
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.56", "", { "os": "darwin", "cpu": "arm64" }, "sha512-x5U9J2k1Fmbb9Mdh1nOd/yZVpg4ARCrV5pFngpaeKrIWDhs8RLpQW3ap+r7uyFLGFkSn4h5wBR0jj6Dg+Tyw+A=="],
|
||||
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.59", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JQWq7W/wkmTujW/2/Ig0d7S+701rul87LSW5txQ+GM4o6EWchqHrELwo6jcZpczsyOEj4fXxI2O8l4OVYyMa9A=="],
|
||||
|
||||
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.56", "", { "os": "darwin", "cpu": "x64" }, "sha512-7swq9rV/SaNVBWoUbC7mlP1VNyKBl7SSwmyVMkcaBP71lkm95zWuh4pgGj82fLgZ9gITRBD95TJVDmTovOyW0A=="],
|
||||
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.59", "", { "os": "darwin", "cpu": "x64" }, "sha512-GzafWzMP9Lt4AzUwQAk02lxgITgfvvo33OLCN265LtQBO8w23u0eB7Fjs9W+nmtcvzXtB9q6HuA0PvP9a3OioA=="],
|
||||
|
||||
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.56", "", { "os": "linux", "cpu": "arm64" }, "sha512-v8b+kiTlynAJzR0hFeVpGFzVi5PGqXAe3Zql9iTiQqTExkm/sR34sfC/P6rBOUhuAnos8ovPDKWtDb6eCTSm9g=="],
|
||||
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.59", "", { "os": "linux", "cpu": "arm64" }, "sha512-QMMFg3dr2v43g3jICgzNFYQyU4YL3zHw733MVJINC+c882+qiQ8l0utTFoVEx/iRYeBzFvMVrKZ4f6G8fFrtrw=="],
|
||||
|
||||
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.56", "", { "os": "linux", "cpu": "x64" }, "sha512-lbxgvAi5SBswK/2hoMPtLhPvJxASgquPUwvGTRHqzDkCvrOChP/loTjBQpL09/nAFc3jbM3SAbZtnEgA2SGYVw=="],
|
||||
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.59", "", { "os": "linux", "cpu": "x64" }, "sha512-XSblVjhW/7+Xs+/o+xJHwHn74nw9j69mnPAFiNdH0d8ilP4j09nUYHZOvQ89sHZaMYeSIuJEciHnh/qP0n5QXQ=="],
|
||||
|
||||
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.56", "", { "os": "win32", "cpu": "arm64" }, "sha512-RoCAbvDo+59OevX+6GrEGbaueERiBVnTaWJkrS41hRAD2fFS3CZpW7UuS5jIg7zn5clHmOGyfvCiBkTRXmgkhw=="],
|
||||
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.59", "", { "os": "win32", "cpu": "arm64" }, "sha512-GU5pPUcTpYmeOUYKpQgAPx0VKBMrfz5LNZlK8gm/jlo2CbLrIW7QLMWCoxncVZmNYqYJeG+KUZkmXYe5KLPXCQ=="],
|
||||
|
||||
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.56", "", { "os": "win32", "cpu": "x64" }, "sha512-i6N5TjZU5gRkJsKmH8e/qY9vwSk0rh6A5t37mHDGlzN4E5yO/MbBrYH4ppLp5stps9Zfi1Re51ofJX1s2hZY/Q=="],
|
||||
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.59", "", { "os": "win32", "cpu": "x64" }, "sha512-InIawEI0TOG8MBBpavMq31WBRBjJ6XPuqFcsDnjqDJcXrRbNkguRW3PNXEwlyaU4tXHfYOsdlPpRtsysS8X/bQ=="],
|
||||
|
||||
"@opentui/solid": ["@opentui/solid@0.1.56", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.56", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-3R7AfxsYHUyehwJK98rt5dI9u2WCT/uH/CYvddZIgXPHyfFm1SHJekMdy3DUoiQTCUllt68eFGKMv9zRi6Laww=="],
|
||||
"@opentui/solid": ["@opentui/solid@0.1.59", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.59", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-O88a/+YHkHlDC4IxbrfWD2ZWlpkpu4oXC2FCLTK8taaUAnLYoybxdrMpv1+o8u8KoWXOoZmEHdntdO9O4abHnQ=="],
|
||||
|
||||
"@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
|
||||
|
||||
@@ -1271,7 +1275,7 @@
|
||||
|
||||
"@petamoriken/float16": ["@petamoriken/float16@3.9.3", "", {}, "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g=="],
|
||||
|
||||
"@pierre/precision-diffs": ["@pierre/precision-diffs@0.6.0-beta.3", "", { "dependencies": { "@shikijs/core": "3.15.0", "@shikijs/transformers": "3.15.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.15.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-1FBm9jhLWZvs7BqN3yG2Wh9SpGuO1us2QsKZlQqSwyCctMr9DRGzYQJ9lF6yR03LHzXs3fuIzO++d9sCObYzrQ=="],
|
||||
"@pierre/precision-diffs": ["@pierre/precision-diffs@0.6.0-beta.10", "", { "dependencies": { "@shikijs/core": "3.15.0", "@shikijs/transformers": "3.15.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "lru_map": "0.4.1", "shiki": "3.15.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-2rdd1Q1xJbB0Z4oUbm0Ybrr2gLFEdvNetZLadJboZSFL7Q4gFujdQZfXfV3vB9X+esjt++v0nzb3mioW25BOTA=="],
|
||||
|
||||
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
||||
|
||||
@@ -1763,21 +1767,21 @@
|
||||
|
||||
"@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="],
|
||||
|
||||
"@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20251014.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20251014.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20251014.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20251014.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20251014.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20251014.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20251014.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20251014.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-IqmX5CYCBqXbfL+HKlcQAMaDlfJ0Z8OhUxvADFV2TENnzSYI4CuhvKxwOB2wFSLXufVsgtAlf3Fjwn24KmMyPQ=="],
|
||||
"@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20251207.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20251207.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20251207.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20251207.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20251207.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20251207.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20251207.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20251207.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-4QcRnzB0pi9rS0AOvg8kWbmuwHv5X7B2EXHbgcms9+56hsZ8SZrZjNgBJb2rUIodJ4kU5mrkj/xlTTT4r9VcpQ=="],
|
||||
|
||||
"@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20251014.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-7rQoLlerWnwnvrM56hP4rdEbo4xDE4zr7cch+EzgENq/tbXYereGq1fmnR83UNglb1Eyy53OvJZ3O2csYBa2vg=="],
|
||||
"@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20251207.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-waWJnuuvkXh4WdpbTjYf7pyahJzx0ycesV2BylyHrE9OxU9FSKcD/cRLQYvbq3YcBSdF7sZwRLDBer7qTeLsYA=="],
|
||||
|
||||
"@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20251014.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-SF29o9NFRGDM23Jz0nVO4/yS78GQ81rtOemmCVNXuJotoY4bP3npGDyEmfkZQHZgDOXogs2OWy3t7NUJ235ANQ=="],
|
||||
"@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20251207.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-3bkD9QuIjxETtp6J1l5X2oKgudJ8z+8fwUq0izCjK1JrIs2vW1aQnbzxhynErSyHWH7URGhHHzcsXHbikckAsg=="],
|
||||
|
||||
"@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20251014.1", "", { "os": "linux", "cpu": "arm" }, "sha512-o5cu7h+BBAp6V4qxYY5RWuaYouN3j+MGFLrrUtvvNj4XKM+kbq5qwsgVRsmJZ1LfUvHmzyQs86vt9djAWedzjQ=="],
|
||||
"@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20251207.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OjrZBq8XJkB7uCQvT1AZ1FPsp+lT0cHxY5SisE+ZTAU6V0IHAZMwJ7J/mnwlGsBcCKRLBT+lX3hgEuOTSwHr9w=="],
|
||||
|
||||
"@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20251014.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-+YWbW/JF4uggEUBr+vflqI5i7bL4Z3XInCOyUO1qQEY7VmfDCsPEzIwGi37O1mixfxw9Qj8LQsptCkU+fqKwGw=="],
|
||||
"@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20251207.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qhp06OObkwy5B+PlAhAmq+Ls3GVt4LHAovrTRcpLB3Mk3yJ0h9DnIQwPQiayp16TdvTsGHI3jdIX4MGm5L/ghA=="],
|
||||
|
||||
"@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20251014.1", "", { "os": "linux", "cpu": "x64" }, "sha512-3LC4tgcgi6zWJWBUpBNXOGSY3yISJrQezSP/T+v+mQRApkdoIpTSHIyQAhgaagcs3MOQRaqiIPaLOVrdHXdU6A=="],
|
||||
"@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20251207.1", "", { "os": "linux", "cpu": "x64" }, "sha512-fPRw0zfTBeVmrkgi5Le+sSwoeAz6pIdvcsa1OYZcrspueS9hn3qSC5bLEc5yX4NJP1vItadBqyGLUQ7u8FJjow=="],
|
||||
|
||||
"@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20251014.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-P0D4UEXwzFZh3pHexe2Ky1tW/HjY/HxTBTIajz2ViDCNPw7uDSEsXSB4H9TTiFJw8gVdTUFbsoAQp1MteTeORA=="],
|
||||
"@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20251207.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-KxY1i+HxeSFfzZ+HVsKwMGBM79laTRZv1ibFqHu22CEsfSPDt4yiV1QFis8Nw7OBXswNqJG/UGqY47VP8FeTvw=="],
|
||||
|
||||
"@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20251014.1", "", { "os": "win32", "cpu": "x64" }, "sha512-fi53g2ihH7tkQLlz8hZGAb2V+3aNZpcxrZ530CQ4xcWwAqssEj0EaZJX0VLEtIQBar1ttGVK9Pz/wJU9sYyVzg=="],
|
||||
"@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20251207.1", "", { "os": "win32", "cpu": "x64" }, "sha512-5l51HlXjX7lXwo65DEl1IaCFLjmkMtL6K3NrSEamPNeNTtTQwZRa3pQ9V65dCglnnCQ0M3+VF1RqzC7FU0iDKg=="],
|
||||
|
||||
"@typescript/vfs": ["@typescript/vfs@1.6.2", "", { "dependencies": { "debug": "^4.1.1" }, "peerDependencies": { "typescript": "*" } }, "sha512-hoBwJwcbKHmvd2QVebiytN1aELvpk9B74B4L1mFm/XT1Q/VOYAWl2vQ9AWRFtQq8zmz6enTpfTV8WRc4ATjW/g=="],
|
||||
|
||||
@@ -1999,7 +2003,7 @@
|
||||
|
||||
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
|
||||
|
||||
"c12": ["c12@2.0.1", "", { "dependencies": { "chokidar": "^4.0.1", "confbox": "^0.1.7", "defu": "^6.1.4", "dotenv": "^16.4.5", "giget": "^1.2.3", "jiti": "^2.3.0", "mlly": "^1.7.1", "ohash": "^1.1.4", "pathe": "^1.1.2", "perfect-debounce": "^1.0.0", "pkg-types": "^1.2.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-Z4JgsKXHG37C6PYUtIxCfLJZvo6FyhHJoClwwb9ftUkLpPSkuYqn6Tr+vnaN8hymm0kIbcg6Ey3kv/Q71k5w/A=="],
|
||||
"c12": ["c12@3.3.2", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.3", "exsolve": "^1.0.8", "giget": "^2.0.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "*" }, "optionalPeers": ["magicast"] }, "sha512-QkikB2X5voO1okL3QsES0N690Sn/K9WokXqUsDQsWy5SnYb+psYQFGA10iy1bZHj3fjISKsI67Q90gruvWWM3A=="],
|
||||
|
||||
"call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="],
|
||||
|
||||
@@ -2081,7 +2085,7 @@
|
||||
|
||||
"comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
|
||||
|
||||
"commander": ["commander@13.0.0", "", {}, "sha512-oPYleIY8wmTVzkvQq10AEok6YcTC4sRUBl8F9gVuwchGVUCTbl/vhLTaQqutuuySYOsu8YTgV+OxKc/8Yvx+mQ=="],
|
||||
"commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="],
|
||||
|
||||
"common-ancestor-path": ["common-ancestor-path@1.0.1", "", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="],
|
||||
|
||||
@@ -2089,7 +2093,7 @@
|
||||
|
||||
"condense-newlines": ["condense-newlines@0.2.1", "", { "dependencies": { "extend-shallow": "^2.0.1", "is-whitespace": "^0.3.0", "kind-of": "^3.0.2" } }, "sha512-P7X+QL9Hb9B/c8HI5BFFKmjgBu2XpQuF98WZ9XkO+dBGgk5XgwiQz7o1SmpglNWId3581UcS0SFAWfoIhMHPfg=="],
|
||||
|
||||
"confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
|
||||
"confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="],
|
||||
|
||||
"config-chain": ["config-chain@1.1.13", "", { "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" } }, "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ=="],
|
||||
|
||||
@@ -2213,7 +2217,7 @@
|
||||
|
||||
"dot-prop": ["dot-prop@8.0.2", "", { "dependencies": { "type-fest": "^3.8.0" } }, "sha512-xaBe6ZT4DHPkg0k4Ytbvn5xoxgpG0jOS1dYxSOwAHPuNLjP3/OzN0gH55SrLqpx8cBfSaVt91lXYkApjb+nYdQ=="],
|
||||
|
||||
"dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
|
||||
"dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="],
|
||||
|
||||
"drizzle-kit": ["drizzle-kit@0.30.5", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.19.7", "esbuild-register": "^3.5.0", "gel": "^2.0.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-l6dMSE100u7sDaTbLczibrQZjA35jLsHNqIV+jmhNVO3O8jzM6kywMOmV9uOz9ZVSCMPQhAZEFjL/qDPVrqpUA=="],
|
||||
|
||||
@@ -2331,6 +2335,8 @@
|
||||
|
||||
"expressive-code": ["expressive-code@0.41.3", "", { "dependencies": { "@expressive-code/core": "^0.41.3", "@expressive-code/plugin-frames": "^0.41.3", "@expressive-code/plugin-shiki": "^0.41.3", "@expressive-code/plugin-text-markers": "^0.41.3" } }, "sha512-YLnD62jfgBZYrXIPQcJ0a51Afv9h8VlWqEGK9uU2T5nL/5rb8SnA86+7+mgCZe5D34Tff5RNEA5hjNVJYHzrFg=="],
|
||||
|
||||
"exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="],
|
||||
|
||||
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
|
||||
|
||||
"extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="],
|
||||
@@ -2393,8 +2399,6 @@
|
||||
|
||||
"fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
|
||||
|
||||
"fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="],
|
||||
|
||||
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
@@ -2441,7 +2445,7 @@
|
||||
|
||||
"gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="],
|
||||
|
||||
"giget": ["giget@1.2.5", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.5.4", "pathe": "^2.0.3", "tar": "^6.2.1" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-r1ekGw/Bgpi3HLV3h1MRBIlSAdHoIMklpaQ3OQLFcRw9PwAj2rqigvIbg+dBUI51OxVI2jsEtDywDBjSiuf7Ug=="],
|
||||
"giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="],
|
||||
|
||||
"github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="],
|
||||
|
||||
@@ -2471,8 +2475,6 @@
|
||||
|
||||
"h3": ["h3@2.0.1-rc.4", "", { "dependencies": { "rou3": "^0.7.8", "srvx": "^0.9.1" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"] }, "sha512-vZq8pEUp6THsXKXrUXX44eOqfChic2wVQ1GlSzQCBr7DeFBkfIZAo2WyNND4GSv54TAa0E4LYIK73WSPdgKUgw=="],
|
||||
|
||||
"handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="],
|
||||
|
||||
"happy-dom": ["happy-dom@20.0.11", "", { "dependencies": { "@types/node": "^20.0.0", "@types/whatwg-mimetype": "^3.0.2", "whatwg-mimetype": "^3.0.0" } }, "sha512-QsCdAUHAmiDeKeaNojb1OHOPF7NjcWPBR7obdu3NwH2a/oyQaLg5d0aaCy/9My6CdPChYF07dvz5chaXBGaD4g=="],
|
||||
|
||||
"has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="],
|
||||
@@ -2537,7 +2539,7 @@
|
||||
|
||||
"hono": ["hono@4.10.7", "", {}, "sha512-icXIITfw/07Q88nLSkB9aiUrd8rYzSweK681Kjo/TSggaGbOX4RRyxxm71v+3PC8C/j+4rlxGeoTRxQDkaJkUw=="],
|
||||
|
||||
"hono-openapi": ["hono-openapi@1.1.1", "", { "peerDependencies": { "@hono/standard-validator": "^0.1.2", "@standard-community/standard-json": "^0.3.5", "@standard-community/standard-openapi": "^0.2.8", "@types/json-schema": "^7.0.15", "hono": "^4.8.3", "openapi-types": "^12.1.3" }, "optionalPeers": ["@hono/standard-validator", "hono"] }, "sha512-AC3HNhZYPHhnZdSy2Je7GDoTTNxPos6rKRQKVDBbSilY3cWJPqsxRnN6zA4pU7tfxmQEMTqkiLXbw6sAaemB8Q=="],
|
||||
"hono-openapi": ["hono-openapi@1.1.2", "", { "peerDependencies": { "@hono/standard-validator": "^0.2.0", "@standard-community/standard-json": "^0.3.5", "@standard-community/standard-openapi": "^0.2.9", "@types/json-schema": "^7.0.15", "hono": "^4.8.3", "openapi-types": "^12.1.3" }, "optionalPeers": ["@hono/standard-validator", "hono"] }, "sha512-toUcO60MftRBxqcVyxsHNYs2m4vf4xkQaiARAucQx3TiBPDtMNNkoh+C4I1vAretQZiGyaLOZNWn1YxfSyUA5g=="],
|
||||
|
||||
"html-entities": ["html-entities@2.3.3", "", {}, "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA=="],
|
||||
|
||||
@@ -2645,6 +2647,8 @@
|
||||
|
||||
"is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="],
|
||||
|
||||
"is-in-ssh": ["is-in-ssh@1.0.0", "", {}, "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw=="],
|
||||
|
||||
"is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="],
|
||||
|
||||
"is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="],
|
||||
@@ -2817,6 +2821,8 @@
|
||||
|
||||
"lru.min": ["lru.min@1.1.3", "", {}, "sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q=="],
|
||||
|
||||
"lru_map": ["lru_map@0.4.1", "", {}, "sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg=="],
|
||||
|
||||
"luxon": ["luxon@3.6.1", "", {}, "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ=="],
|
||||
|
||||
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
||||
@@ -2983,8 +2989,6 @@
|
||||
|
||||
"mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="],
|
||||
|
||||
"mlly": ["mlly@1.8.0", "", { "dependencies": { "acorn": "^8.15.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.1" } }, "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g=="],
|
||||
|
||||
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
@@ -3003,8 +3007,6 @@
|
||||
|
||||
"negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
|
||||
|
||||
"neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="],
|
||||
|
||||
"neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="],
|
||||
|
||||
"nf3": ["nf3@0.1.12", "", {}, "sha512-qbMXT7RTGh74MYWPeqTIED8nDW70NXOULVHpdWcdZ7IVHVnAsMV9fNugSNnvooipDc1FMOzpis7T9nXJEbJhvQ=="],
|
||||
@@ -3043,7 +3045,7 @@
|
||||
|
||||
"nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="],
|
||||
|
||||
"nypm": ["nypm@0.5.4", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "tinyexec": "^0.3.2", "ufo": "^1.5.4" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-X0SNNrZiGU8/e/zAB7sCTtdxWTMSIO73q+xuKgglm2Yvzwlo8UoC5FNySQFCvl84uPaeADkqHUZUkWy4aH4xOA=="],
|
||||
"nypm": ["nypm@0.6.2", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.2", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "tinyexec": "^1.0.1" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g=="],
|
||||
|
||||
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
||||
|
||||
@@ -3159,7 +3161,7 @@
|
||||
|
||||
"peek-readable": ["peek-readable@4.1.0", "", {}, "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg=="],
|
||||
|
||||
"perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="],
|
||||
"perfect-debounce": ["perfect-debounce@2.0.0", "", {}, "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow=="],
|
||||
|
||||
"piccolore": ["piccolore@0.1.3", "", {}, "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw=="],
|
||||
|
||||
@@ -3177,7 +3179,7 @@
|
||||
|
||||
"pkg-dir": ["pkg-dir@4.2.0", "", { "dependencies": { "find-up": "^4.0.0" } }, "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ=="],
|
||||
|
||||
"pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
|
||||
"pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="],
|
||||
|
||||
"pkg-up": ["pkg-up@3.1.0", "", { "dependencies": { "find-up": "^3.0.0" } }, "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA=="],
|
||||
|
||||
@@ -3205,6 +3207,8 @@
|
||||
|
||||
"postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="],
|
||||
|
||||
"powershell-utils": ["powershell-utils@0.1.0", "", {}, "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A=="],
|
||||
|
||||
"prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="],
|
||||
|
||||
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
|
||||
@@ -3459,7 +3463,7 @@
|
||||
|
||||
"solid-use": ["solid-use@0.9.1", "", { "peerDependencies": { "solid-js": "^1.7" } }, "sha512-UwvXDVPlrrbj/9ewG9ys5uL2IO4jSiwys2KPzK4zsnAcmEl7iDafZWW1Mo4BSEWOmQCGK6IvpmGHo1aou8iOFw=="],
|
||||
|
||||
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
"source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
||||
|
||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||
|
||||
@@ -3659,8 +3663,6 @@
|
||||
|
||||
"ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="],
|
||||
|
||||
"uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="],
|
||||
|
||||
"ulid": ["ulid@3.0.1", "", { "bin": { "ulid": "dist/cli.js" } }, "sha512-dPJyqPzx8preQhqq24bBG1YNkvigm87K8kVEHCD+ruZg24t6IFEFv00xMWfxcC4djmFtiTLdFuADn4+DOz6R7Q=="],
|
||||
|
||||
"ultrahtml": ["ultrahtml@1.6.0", "", {}, "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw=="],
|
||||
@@ -3789,8 +3791,6 @@
|
||||
|
||||
"widest-line": ["widest-line@5.0.0", "", { "dependencies": { "string-width": "^7.0.0" } }, "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA=="],
|
||||
|
||||
"wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="],
|
||||
|
||||
"workerd": ["workerd@1.20251118.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20251118.0", "@cloudflare/workerd-darwin-arm64": "1.20251118.0", "@cloudflare/workerd-linux-64": "1.20251118.0", "@cloudflare/workerd-linux-arm64": "1.20251118.0", "@cloudflare/workerd-windows-64": "1.20251118.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-Om5ns0Lyx/LKtYI04IV0bjIrkBgoFNg0p6urzr2asekJlfP18RqFzyqMFZKf0i9Gnjtz/JfAS/Ol6tjCe5JJsQ=="],
|
||||
|
||||
"wrangler": ["wrangler@4.50.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.7.11", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20251118.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20251118.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20251118.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-+nuZuHZxDdKmAyXOSrHlciGshCoAPiy5dM+t6mEohWm7HpXvTHmWQGUf/na9jjWlWJHCJYOWzkA1P5HBJqrIEA=="],
|
||||
@@ -3803,6 +3803,8 @@
|
||||
|
||||
"ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
|
||||
|
||||
"wsl-utils": ["wsl-utils@0.3.0", "", { "dependencies": { "is-wsl": "^3.1.0", "powershell-utils": "^0.1.0" } }, "sha512-3sFIGLiaDP7rTO4xh3g+b3AzhYDIUGGywE/WsmqzJWDxus5aJXVnPTNC/6L+r2WzrwXqVOdD262OaO+cEyPMSQ=="],
|
||||
|
||||
"xdg-basedir": ["xdg-basedir@5.1.0", "", {}, "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ=="],
|
||||
|
||||
"xml-parse-from-string": ["xml-parse-from-string@1.0.1", "", {}, "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g=="],
|
||||
@@ -3897,8 +3899,6 @@
|
||||
|
||||
"@astrojs/mdx/@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.9", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.5", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.0", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.13.0", "smol-toml": "^1.4.2", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, "sha512-hX2cLC/KW74Io1zIbn92kI482j9J7LleBLGCVU9EP3BeH5MVrnFawOnqD0t/q6D1Z+ZNeQG2gNKMslCcO36wng=="],
|
||||
|
||||
"@astrojs/mdx/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
||||
|
||||
"@astrojs/sitemap/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||
|
||||
"@astrojs/solid-js/vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
|
||||
@@ -3985,6 +3985,10 @@
|
||||
|
||||
"@expressive-code/plugin-shiki/shiki": ["shiki@3.15.0", "", { "dependencies": { "@shikijs/core": "3.15.0", "@shikijs/engine-javascript": "3.15.0", "@shikijs/engine-oniguruma": "3.15.0", "@shikijs/langs": "3.15.0", "@shikijs/themes": "3.15.0", "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-kLdkY6iV3dYbtPwS9KXU7mjfmDm25f5m0IPNFnaXO7TBPcvbUOY72PYXSuSqDzwp+vlH/d7MXpHlKO/x+QoLXw=="],
|
||||
|
||||
"@hey-api/json-schema-ref-parser/js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
|
||||
|
||||
"@hey-api/openapi-ts/open": ["open@11.0.0", "", { "dependencies": { "default-browser": "^5.4.0", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.1.0", "wsl-utils": "^0.3.0" } }, "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw=="],
|
||||
|
||||
"@hono/zod-validator/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||
|
||||
"@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
|
||||
@@ -4031,8 +4035,6 @@
|
||||
|
||||
"@jsx-email/doiuse-email/htmlparser2": ["htmlparser2@9.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.1.0", "entities": "^4.5.0" } }, "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ=="],
|
||||
|
||||
"@mdx-js/mdx/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
||||
|
||||
"@modelcontextprotocol/sdk/express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="],
|
||||
|
||||
"@modelcontextprotocol/sdk/raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="],
|
||||
@@ -4177,9 +4179,7 @@
|
||||
|
||||
"boxen/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||
|
||||
"c12/ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="],
|
||||
|
||||
"c12/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
|
||||
"clean-css/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
|
||||
"compress-commons/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
|
||||
|
||||
@@ -4199,8 +4199,6 @@
|
||||
|
||||
"esbuild-plugin-copy/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
||||
|
||||
"estree-util-to-js/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
||||
|
||||
"execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="],
|
||||
|
||||
"express/cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="],
|
||||
@@ -4215,14 +4213,10 @@
|
||||
|
||||
"form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
|
||||
|
||||
"fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||
|
||||
"gaxios/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
|
||||
|
||||
"gaxios/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
|
||||
|
||||
"giget/tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
|
||||
|
||||
"glob/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="],
|
||||
|
||||
"globby/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
||||
@@ -4259,6 +4253,8 @@
|
||||
|
||||
"npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
|
||||
|
||||
"nypm/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="],
|
||||
|
||||
"opencode/@ai-sdk/anthropic": ["@ai-sdk/anthropic@2.0.50", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.18" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-21PaHfoLmouOXXNINTsZJsMw+wE5oLR2He/1kq/sKokTVKyq7ObGT1LDk6ahwxaz/GoaNaGankMh+EgVcdv2Cw=="],
|
||||
|
||||
"opencode/@ai-sdk/openai": ["@ai-sdk/openai@2.0.71", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.17" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-tg+gj+R0z/On9P4V7hy7/7o04cQPjKGayMCL3gzWD/aNGjAKkhEnaocuNDidSnghizt8g2zJn16cAuAolnW+qQ=="],
|
||||
@@ -4319,6 +4315,8 @@
|
||||
|
||||
"sitemap/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="],
|
||||
|
||||
"source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
|
||||
"sst/aws4fetch": ["aws4fetch@1.0.18", "", {}, "sha512-3Cf+YaUl07p24MoQ46rFwulAmiyCwH2+1zw1ZyPAX5OtJ34Hh185DwB8y/qRLb6cYYYtSFJ9pthyLc0MD4e8sQ=="],
|
||||
|
||||
"sst/jose": ["jose@5.2.3", "", {}, "sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA=="],
|
||||
@@ -4823,14 +4821,6 @@
|
||||
|
||||
"form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
|
||||
|
||||
"giget/tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
|
||||
|
||||
"giget/tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="],
|
||||
|
||||
"giget/tar/minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="],
|
||||
|
||||
"giget/tar/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
|
||||
|
||||
"gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
|
||||
|
||||
"js-beautify/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
|
||||
@@ -5007,8 +4997,6 @@
|
||||
|
||||
"esbuild-plugin-copy/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"giget/tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||
|
||||
"js-beautify/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||
|
||||
"opencontrol/@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"nodeModules": "sha256-7eJpUUtS50/uHa6sU0pl/MbwJykkVlYwEeAoKKNk4+g="
|
||||
"nodeModules": "sha256-IzF5XDY09Z1p/8jgYIHhE/jpKPub15KKUpV+a/aKpuc="
|
||||
}
|
||||
|
||||
@@ -30,16 +30,16 @@
|
||||
"@tsconfig/bun": "1.0.9",
|
||||
"@cloudflare/workers-types": "4.20251008.0",
|
||||
"@openauthjs/openauth": "0.0.0-20250322224806",
|
||||
"@pierre/precision-diffs": "0.6.0-beta.3",
|
||||
"@pierre/precision-diffs": "0.6.0-beta.10",
|
||||
"@tailwindcss/vite": "4.1.11",
|
||||
"diff": "8.0.2",
|
||||
"ai": "5.0.97",
|
||||
"hono": "4.10.7",
|
||||
"hono-openapi": "1.1.1",
|
||||
"hono-openapi": "1.1.2",
|
||||
"fuzzysort": "3.1.0",
|
||||
"luxon": "3.6.1",
|
||||
"typescript": "5.8.2",
|
||||
"@typescript/native-preview": "7.0.0-dev.20251014.1",
|
||||
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|
||||
"zod": "4.1.8",
|
||||
"remeda": "2.26.0",
|
||||
"solid-list": "0.3.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/console-core",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-function",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-mail",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"dependencies": {
|
||||
"@jsx-email/all": "2.2.3",
|
||||
"@jsx-email/cli": "1.4.3",
|
||||
|
||||
@@ -23,6 +23,6 @@
|
||||
</script>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<script src="/src/index.tsx" type="module"></script>
|
||||
<script src="/src/entry.tsx" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "@opencode-ai/desktop",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./src/index.tsx",
|
||||
".": "./src/index.ts",
|
||||
"./vite": "./vite.js"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
67
packages/desktop/src/DesktopInterface.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import "@/index.css"
|
||||
import { Router, Route, Navigate } from "@solidjs/router"
|
||||
import { MetaProvider } from "@solidjs/meta"
|
||||
import { Font } from "@opencode-ai/ui/font"
|
||||
import { Favicon } from "@opencode-ai/ui/favicon"
|
||||
import { MarkedProvider } from "@opencode-ai/ui/context/marked"
|
||||
import { DiffComponentProvider } from "@opencode-ai/ui/context/diff"
|
||||
import { Diff } from "@opencode-ai/ui/diff"
|
||||
import { GlobalSyncProvider, useGlobalSync } from "./context/global-sync"
|
||||
import Layout from "@/pages/layout"
|
||||
import DirectoryLayout from "@/pages/directory-layout"
|
||||
import Session from "@/pages/session"
|
||||
import { LayoutProvider } from "./context/layout"
|
||||
import { GlobalSDKProvider } from "./context/global-sdk"
|
||||
import { SessionProvider } from "./context/session"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { createMemo, Show } from "solid-js"
|
||||
|
||||
const host = import.meta.env.VITE_OPENCODE_SERVER_HOST ?? "127.0.0.1"
|
||||
const port = import.meta.env.VITE_OPENCODE_SERVER_PORT ?? "4096"
|
||||
|
||||
const url =
|
||||
new URLSearchParams(document.location.search).get("url") ||
|
||||
(location.hostname.includes("opencode.ai") || location.hostname.includes("localhost")
|
||||
? `http://${host}:${port}`
|
||||
: "/")
|
||||
|
||||
export function DesktopInterface() {
|
||||
return (
|
||||
<MarkedProvider>
|
||||
<DiffComponentProvider component={Diff}>
|
||||
<GlobalSDKProvider url={url}>
|
||||
<GlobalSyncProvider>
|
||||
<LayoutProvider>
|
||||
<MetaProvider>
|
||||
<Font />
|
||||
<Router root={Layout}>
|
||||
<Route
|
||||
path="/"
|
||||
component={() => {
|
||||
const globalSync = useGlobalSync()
|
||||
const slug = createMemo(() => base64Encode(globalSync.data.defaultProject!.worktree))
|
||||
return <Navigate href={`${slug()}/session`} />
|
||||
}}
|
||||
/>
|
||||
<Route path="/:dir" component={DirectoryLayout}>
|
||||
<Route path="/" component={() => <Navigate href="session" />} />
|
||||
<Route
|
||||
path="/session/:id?"
|
||||
component={(p) => (
|
||||
<Show when={p.params.id || true} keyed>
|
||||
<SessionProvider>
|
||||
<Session />
|
||||
</SessionProvider>
|
||||
</Show>
|
||||
)}
|
||||
/>
|
||||
</Route>
|
||||
</Router>
|
||||
</MetaProvider>
|
||||
</LayoutProvider>
|
||||
</GlobalSyncProvider>
|
||||
</GlobalSDKProvider>
|
||||
</DiffComponentProvider>
|
||||
</MarkedProvider>
|
||||
)
|
||||
}
|
||||
14
packages/desktop/src/PlatformContext.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import { createContext } from "solid-js"
|
||||
import { useContext } from "solid-js"
|
||||
|
||||
export interface Platform {}
|
||||
|
||||
const PlatformContext = createContext<Platform>()
|
||||
|
||||
export const PlatformProvider = PlatformContext.Provider
|
||||
|
||||
export function usePlatform() {
|
||||
const ctx = useContext(PlatformContext)
|
||||
if (!ctx) throw new Error("usePlatform must be used within a PlatformProvider")
|
||||
return ctx
|
||||
}
|
||||
@@ -235,9 +235,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
|
||||
const abort = () =>
|
||||
sdk.client.session.abort({
|
||||
path: {
|
||||
id: session.id!,
|
||||
},
|
||||
sessionID: session.id!,
|
||||
})
|
||||
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
@@ -329,21 +327,19 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||
session.prompt.set([{ type: "text", content: "", start: 0, end: 0 }], 0)
|
||||
|
||||
sdk.client.session.prompt({
|
||||
path: { id: existing.id },
|
||||
body: {
|
||||
agent: local.agent.current()!.name,
|
||||
model: {
|
||||
modelID: local.model.current()!.id,
|
||||
providerID: local.model.current()!.provider.id,
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
type: "text",
|
||||
text,
|
||||
},
|
||||
...attachmentParts,
|
||||
],
|
||||
sessionID: existing.id,
|
||||
agent: local.agent.current()!.name,
|
||||
model: {
|
||||
modelID: local.model.current()!.id,
|
||||
providerID: local.model.current()!.provider.id,
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
type: "text",
|
||||
text,
|
||||
},
|
||||
...attachmentParts,
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -74,12 +74,10 @@ export const Terminal = (props: TerminalProps) => {
|
||||
term.onResize(async (size) => {
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
await sdk.client.pty.update({
|
||||
path: { id: local.pty.id },
|
||||
body: {
|
||||
size: {
|
||||
cols: size.cols,
|
||||
rows: size.rows,
|
||||
},
|
||||
ptyID: local.pty.id,
|
||||
size: {
|
||||
cols: size.cols,
|
||||
rows: size.rows,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -100,12 +98,10 @@ export const Terminal = (props: TerminalProps) => {
|
||||
ws.addEventListener("open", () => {
|
||||
console.log("WebSocket connected")
|
||||
sdk.client.pty.update({
|
||||
path: { id: local.pty.id },
|
||||
body: {
|
||||
size: {
|
||||
cols: term.cols,
|
||||
rows: term.rows,
|
||||
},
|
||||
ptyID: local.pty.id,
|
||||
size: {
|
||||
cols: term.cols,
|
||||
rows: term.rows,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createOpencodeClient, type Event } from "@opencode-ai/sdk/client"
|
||||
import { createOpencodeClient, type Event } from "@opencode-ai/sdk/v2/client"
|
||||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||
import { createGlobalEmitter } from "@solid-primitives/event-bus"
|
||||
import { onCleanup } from "solid-js"
|
||||
|
||||
@@ -12,7 +12,7 @@ import type {
|
||||
FileDiff,
|
||||
Todo,
|
||||
SessionStatus,
|
||||
} from "@opencode-ai/sdk"
|
||||
} from "@opencode-ai/sdk/v2"
|
||||
import { createStore, produce, reconcile } from "solid-js/store"
|
||||
import { Binary } from "@opencode-ai/util/binary"
|
||||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { createStore, produce, reconcile } from "solid-js/store"
|
||||
import { batch, createEffect, createMemo } from "solid-js"
|
||||
import { uniqueBy } from "remeda"
|
||||
import type { FileContent, FileNode, Model, Provider, File as FileStatus } from "@opencode-ai/sdk"
|
||||
import type { FileContent, FileNode, Model, Provider, File as FileStatus } from "@opencode-ai/sdk/v2"
|
||||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||
import { useSDK } from "./sdk"
|
||||
import { useSync } from "./sync"
|
||||
import { base64Encode } from "@/utils"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
|
||||
export type LocalFile = FileNode &
|
||||
Partial<{
|
||||
@@ -257,7 +257,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
|
||||
const load = async (path: string) => {
|
||||
const relativePath = relative(path)
|
||||
sdk.client.file.read({ query: { path: relativePath } }).then((x) => {
|
||||
sdk.client.file.read({ path: relativePath }).then((x) => {
|
||||
setStore(
|
||||
"node",
|
||||
relativePath,
|
||||
@@ -305,7 +305,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
}
|
||||
|
||||
const list = async (path: string) => {
|
||||
return sdk.client.file.list({ query: { path: path + "/" } }).then((x) => {
|
||||
return sdk.client.file.list({ path: path + "/" }).then((x) => {
|
||||
setStore(
|
||||
"node",
|
||||
produce((draft) => {
|
||||
@@ -318,10 +318,9 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
})
|
||||
}
|
||||
|
||||
const searchFiles = (query: string) =>
|
||||
sdk.client.find.files({ query: { query, dirs: "false" } }).then((x) => x.data!)
|
||||
const searchFiles = (query: string) => sdk.client.find.files({ query, dirs: "false" }).then((x) => x.data!)
|
||||
const searchFilesAndDirectories = (query: string) =>
|
||||
sdk.client.find.files({ query: { query, dirs: "true" } }).then((x) => x.data!)
|
||||
sdk.client.find.files({ query, dirs: "true" }).then((x) => x.data!)
|
||||
|
||||
sdk.event.listen((e) => {
|
||||
const event = e.details
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createOpencodeClient, type Event } from "@opencode-ai/sdk/client"
|
||||
import { createOpencodeClient, type Event } from "@opencode-ai/sdk/v2/client"
|
||||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||
import { createGlobalEmitter } from "@solid-primitives/event-bus"
|
||||
import { onCleanup } from "solid-js"
|
||||
|
||||
@@ -5,9 +5,9 @@ import { useSync } from "./sync"
|
||||
import { makePersisted } from "@solid-primitives/storage"
|
||||
import { TextSelection } from "./local"
|
||||
import { pipe, sumBy } from "remeda"
|
||||
import { AssistantMessage, UserMessage } from "@opencode-ai/sdk"
|
||||
import { AssistantMessage, UserMessage } from "@opencode-ai/sdk/v2"
|
||||
import { useParams } from "@solidjs/router"
|
||||
import { base64Encode } from "@/utils"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { useSDK } from "./sdk"
|
||||
|
||||
export type LocalPTY = {
|
||||
@@ -26,7 +26,7 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
|
||||
const params = useParams()
|
||||
const sync = useSync()
|
||||
const name = createMemo(
|
||||
() => `${base64Encode(sync.data.project.worktree)}/session${params.id ? "/" + params.id : ""}.v1`,
|
||||
() => `${base64Encode(sync.data.project.worktree)}/session${params.id ? "/" + params.id : ""}.v2`,
|
||||
)
|
||||
|
||||
const [store, setStore] = makePersisted(
|
||||
@@ -198,7 +198,7 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
|
||||
all: createMemo(() => Object.values(store.terminals.all)),
|
||||
active: createMemo(() => store.terminals.active),
|
||||
new() {
|
||||
sdk.client.pty.create({ body: { title: `Terminal ${store.terminals.all.length + 1}` } }).then((pty) => {
|
||||
sdk.client.pty.create({ title: `Terminal ${store.terminals.all.length + 1}` }).then((pty) => {
|
||||
const id = pty.data?.id
|
||||
if (!id) return
|
||||
setStore("terminals", "all", [
|
||||
@@ -214,8 +214,9 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
|
||||
update(pty: Partial<LocalPTY> & { id: string }) {
|
||||
setStore("terminals", "all", (x) => x.map((x) => (x.id === pty.id ? { ...x, ...pty } : x)))
|
||||
sdk.client.pty.update({
|
||||
path: { id: pty.id },
|
||||
body: { title: pty.title, size: pty.cols && pty.rows ? { rows: pty.rows, cols: pty.cols } : undefined },
|
||||
ptyID: pty.id,
|
||||
title: pty.title,
|
||||
size: pty.cols && pty.rows ? { rows: pty.rows, cols: pty.cols } : undefined,
|
||||
})
|
||||
},
|
||||
async clone(id: string) {
|
||||
@@ -223,9 +224,7 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
|
||||
const pty = store.terminals.all[index]
|
||||
if (!pty) return
|
||||
const clone = await sdk.client.pty.create({
|
||||
body: {
|
||||
title: pty.title,
|
||||
},
|
||||
title: pty.title,
|
||||
})
|
||||
if (!clone.data) return
|
||||
setStore("terminals", "all", index, {
|
||||
@@ -252,7 +251,7 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
|
||||
setStore("terminals", "active", previous)
|
||||
}
|
||||
})
|
||||
await sdk.client.pty.remove({ path: { id } })
|
||||
await sdk.client.pty.remove({ ptyID: id })
|
||||
},
|
||||
move(id: string, to: number) {
|
||||
const index = store.terminals.all.findIndex((f) => f.id === id)
|
||||
|
||||
@@ -28,7 +28,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
status: () => sdk.client.session.status().then((x) => setStore("session_status", x.data!)),
|
||||
config: () => sdk.client.config.get().then((x) => setStore("config", x.data!)),
|
||||
changes: () => sdk.client.file.status().then((x) => setStore("changes", x.data!)),
|
||||
node: () => sdk.client.file.list({ query: { path: "/" } }).then((x) => setStore("node", x.data!)),
|
||||
node: () => sdk.client.file.list({ path: "/" }).then((x) => setStore("node", x.data!)),
|
||||
}
|
||||
|
||||
Promise.all(Object.values(load).map((p) => p())).then(() => setStore("ready", true))
|
||||
@@ -49,10 +49,10 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
},
|
||||
async sync(sessionID: string, _isRetry = false) {
|
||||
const [session, messages, todo, diff] = await Promise.all([
|
||||
sdk.client.session.get({ path: { id: sessionID }, throwOnError: true }),
|
||||
sdk.client.session.messages({ path: { id: sessionID }, query: { limit: 100 } }),
|
||||
sdk.client.session.todo({ path: { id: sessionID } }),
|
||||
sdk.client.session.diff({ path: { id: sessionID } }),
|
||||
sdk.client.session.get({ sessionID }, { throwOnError: true }),
|
||||
sdk.client.session.messages({ sessionID, limit: 100 }),
|
||||
sdk.client.session.todo({ sessionID }),
|
||||
sdk.client.session.diff({ sessionID }),
|
||||
])
|
||||
setStore(
|
||||
produce((draft) => {
|
||||
|
||||
22
packages/desktop/src/entry.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
// @refresh reload
|
||||
import { render } from "solid-js/web"
|
||||
import { DesktopInterface } from "@/DesktopInterface"
|
||||
import { Platform, PlatformProvider } from "@/PlatformContext"
|
||||
|
||||
const root = document.getElementById("root")
|
||||
if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
|
||||
throw new Error(
|
||||
"Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got misspelled?",
|
||||
)
|
||||
}
|
||||
|
||||
const platform: Platform = {}
|
||||
|
||||
render(
|
||||
() => (
|
||||
<PlatformProvider value={platform}>
|
||||
<DesktopInterface />
|
||||
</PlatformProvider>
|
||||
),
|
||||
root!,
|
||||
)
|
||||
2
packages/desktop/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { PlatformProvider, type Platform } from "./PlatformContext"
|
||||
export { DesktopInterface } from "./DesktopInterface"
|
||||
@@ -1,73 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import "@/index.css"
|
||||
import { render } from "solid-js/web"
|
||||
import { Router, Route, Navigate } from "@solidjs/router"
|
||||
import { MetaProvider } from "@solidjs/meta"
|
||||
import { Font } from "@opencode-ai/ui/font"
|
||||
import { Favicon } from "@opencode-ai/ui/favicon"
|
||||
import { MarkedProvider } from "@opencode-ai/ui/context/marked"
|
||||
import { GlobalSyncProvider, useGlobalSync } from "./context/global-sync"
|
||||
import Layout from "@/pages/layout"
|
||||
import DirectoryLayout from "@/pages/directory-layout"
|
||||
import Session from "@/pages/session"
|
||||
import { LayoutProvider } from "./context/layout"
|
||||
import { GlobalSDKProvider } from "./context/global-sdk"
|
||||
import { SessionProvider } from "./context/session"
|
||||
import { base64Encode } from "./utils"
|
||||
import { createMemo, Show } from "solid-js"
|
||||
|
||||
const host = import.meta.env.VITE_OPENCODE_SERVER_HOST ?? "127.0.0.1"
|
||||
const port = import.meta.env.VITE_OPENCODE_SERVER_PORT ?? "4096"
|
||||
|
||||
const url =
|
||||
new URLSearchParams(document.location.search).get("url") ||
|
||||
(location.hostname.includes("opencode.ai") || location.hostname.includes("localhost")
|
||||
? `http://${host}:${port}`
|
||||
: "/")
|
||||
|
||||
const root = document.getElementById("root")
|
||||
if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
|
||||
throw new Error(
|
||||
"Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got misspelled?",
|
||||
)
|
||||
}
|
||||
|
||||
render(
|
||||
() => (
|
||||
<MarkedProvider>
|
||||
<GlobalSDKProvider url={url}>
|
||||
<GlobalSyncProvider>
|
||||
<LayoutProvider>
|
||||
<MetaProvider>
|
||||
<Font />
|
||||
<Router root={Layout}>
|
||||
<Route
|
||||
path="/"
|
||||
component={() => {
|
||||
const globalSync = useGlobalSync()
|
||||
const slug = createMemo(() => base64Encode(globalSync.data.defaultProject!.worktree))
|
||||
return <Navigate href={`${slug()}/session`} />
|
||||
}}
|
||||
/>
|
||||
<Route path="/:dir" component={DirectoryLayout}>
|
||||
<Route path="/" component={() => <Navigate href="session" />} />
|
||||
<Route
|
||||
path="/session/:id?"
|
||||
component={(p) => (
|
||||
<Show when={p.params.id || true} keyed>
|
||||
<SessionProvider>
|
||||
<Session />
|
||||
</SessionProvider>
|
||||
</Show>
|
||||
)}
|
||||
/>
|
||||
</Route>
|
||||
</Router>
|
||||
</MetaProvider>
|
||||
</LayoutProvider>
|
||||
</GlobalSyncProvider>
|
||||
</GlobalSDKProvider>
|
||||
</MarkedProvider>
|
||||
),
|
||||
root!,
|
||||
)
|
||||
@@ -4,7 +4,7 @@ import { SDKProvider } from "@/context/sdk"
|
||||
import { SyncProvider, useSync } from "@/context/sync"
|
||||
import { LocalProvider } from "@/context/local"
|
||||
import { useGlobalSync } from "@/context/global-sync"
|
||||
import { base64Decode } from "@/utils"
|
||||
import { base64Decode } from "@opencode-ai/util/encode"
|
||||
import { DataProvider } from "@opencode-ai/ui/context"
|
||||
import { iife } from "@opencode-ai/util/iife"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useGlobalSync } from "@/context/global-sync"
|
||||
import { base64Encode } from "@/utils"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { For } from "solid-js"
|
||||
import { A } from "@solidjs/router"
|
||||
import { Button } from "@opencode-ai/ui/button"
|
||||
|
||||
@@ -3,8 +3,9 @@ import { DateTime } from "luxon"
|
||||
import { A, useNavigate, useParams } from "@solidjs/router"
|
||||
import { useLayout } from "@/context/layout"
|
||||
import { useGlobalSync } from "@/context/global-sync"
|
||||
import { base64Decode, base64Encode } from "@/utils"
|
||||
import { base64Decode, base64Encode } from "@opencode-ai/util/encode"
|
||||
import { Mark } from "@opencode-ai/ui/logo"
|
||||
import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
|
||||
import { Button } from "@opencode-ai/ui/button"
|
||||
import { Icon } from "@opencode-ai/ui/icon"
|
||||
import { IconButton } from "@opencode-ai/ui/icon-button"
|
||||
@@ -13,7 +14,7 @@ import { Collapsible } from "@opencode-ai/ui/collapsible"
|
||||
import { DiffChanges } from "@opencode-ai/ui/diff-changes"
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import { Select } from "@opencode-ai/ui/select"
|
||||
import { Session } from "@opencode-ai/sdk/client"
|
||||
import { Session } from "@opencode-ai/sdk/v2/client"
|
||||
|
||||
export default function Layout(props: ParentProps) {
|
||||
const navigate = useNavigate()
|
||||
@@ -65,7 +66,7 @@ export default function Layout(props: ParentProps) {
|
||||
label={(x) => x.title}
|
||||
value={(x) => x.id}
|
||||
onSelect={navigateToSession}
|
||||
class="text-14-regular text-text-base max-w-3xs"
|
||||
class="text-14-regular text-text-base max-w-md"
|
||||
variant="ghost"
|
||||
/>
|
||||
</div>
|
||||
@@ -116,41 +117,14 @@ export default function Layout(props: ParentProps) {
|
||||
style={{ width: layout.sidebar.opened() ? `${layout.sidebar.width()}px` : undefined }}
|
||||
>
|
||||
<Show when={layout.sidebar.opened()}>
|
||||
<div
|
||||
class="absolute inset-y-0 right-0 z-10 w-2 translate-x-1/2 cursor-ew-resize"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault()
|
||||
const startX = e.clientX
|
||||
const startWidth = layout.sidebar.width()
|
||||
const maxWidth = window.innerWidth * 0.3
|
||||
const minWidth = 150
|
||||
const collapseThreshold = 80
|
||||
let currentWidth = startWidth
|
||||
|
||||
document.body.style.userSelect = "none"
|
||||
document.body.style.overflow = "hidden"
|
||||
|
||||
const onMouseMove = (moveEvent: MouseEvent) => {
|
||||
const deltaX = moveEvent.clientX - startX
|
||||
currentWidth = startWidth + deltaX
|
||||
const clampedWidth = Math.min(maxWidth, Math.max(minWidth, currentWidth))
|
||||
layout.sidebar.resize(clampedWidth)
|
||||
}
|
||||
|
||||
const onMouseUp = () => {
|
||||
document.body.style.userSelect = ""
|
||||
document.body.style.overflow = ""
|
||||
document.removeEventListener("mousemove", onMouseMove)
|
||||
document.removeEventListener("mouseup", onMouseUp)
|
||||
|
||||
if (currentWidth < collapseThreshold) {
|
||||
layout.sidebar.close()
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("mousemove", onMouseMove)
|
||||
document.addEventListener("mouseup", onMouseUp)
|
||||
}}
|
||||
<ResizeHandle
|
||||
direction="horizontal"
|
||||
size={layout.sidebar.width()}
|
||||
min={150}
|
||||
max={window.innerWidth * 0.3}
|
||||
collapseThreshold={80}
|
||||
onResize={layout.sidebar.resize}
|
||||
onCollapse={layout.sidebar.close}
|
||||
/>
|
||||
</Show>
|
||||
<div class="grow flex flex-col items-start self-stretch gap-4 p-2 min-h-0">
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Icon } from "@opencode-ai/ui/icon"
|
||||
import { Tooltip } from "@opencode-ai/ui/tooltip"
|
||||
import { DiffChanges } from "@opencode-ai/ui/diff-changes"
|
||||
import { ProgressCircle } from "@opencode-ai/ui/progress-circle"
|
||||
import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
|
||||
import { Tabs } from "@opencode-ai/ui/tabs"
|
||||
import { Code } from "@opencode-ai/ui/code"
|
||||
import { SessionTurn } from "@opencode-ai/ui/session-turn"
|
||||
@@ -30,8 +31,8 @@ import { useSync } from "@/context/sync"
|
||||
import { useSession } from "@/context/session"
|
||||
import { useLayout } from "@/context/layout"
|
||||
import { getDirectory, getFilename } from "@opencode-ai/util/path"
|
||||
import { Diff } from "@opencode-ai/ui/diff"
|
||||
import { Terminal } from "@/components/terminal"
|
||||
import { checksum } from "@opencode-ai/util/encode"
|
||||
|
||||
export default function Page() {
|
||||
const layout = useLayout()
|
||||
@@ -282,7 +283,7 @@ export default function Page() {
|
||||
const wide = createMemo(() => layout.review.state() === "tab" || !session.diffs().length)
|
||||
|
||||
return (
|
||||
<div class="relative bg-background-base size-full overflow-x-hidden flex flex-col items-start">
|
||||
<div class="relative bg-background-base size-full overflow-x-hidden flex flex-col">
|
||||
<div class="min-h-0 grow w-full">
|
||||
<DragDropProvider
|
||||
onDragStart={handleDragStart}
|
||||
@@ -389,7 +390,6 @@ export default function Page() {
|
||||
? "pr-6 pl-18"
|
||||
: "px-6"),
|
||||
}}
|
||||
diffComponent={Diff}
|
||||
/>
|
||||
</div>
|
||||
</Match>
|
||||
@@ -438,7 +438,6 @@ export default function Page() {
|
||||
container: "px-6",
|
||||
}}
|
||||
diffs={session.diffs()}
|
||||
diffComponent={Diff}
|
||||
actions={
|
||||
<Tooltip value="Open in tab">
|
||||
<IconButton
|
||||
@@ -470,7 +469,6 @@ export default function Page() {
|
||||
container: "px-6",
|
||||
}}
|
||||
diffs={session.diffs()}
|
||||
diffComponent={Diff}
|
||||
split
|
||||
/>
|
||||
</div>
|
||||
@@ -493,7 +491,11 @@ export default function Page() {
|
||||
<Match when={file()}>
|
||||
{(f) => (
|
||||
<Code
|
||||
file={{ name: f().path, contents: f().content?.content ?? "" }}
|
||||
file={{
|
||||
name: f().path,
|
||||
contents: f().content?.content ?? "",
|
||||
cacheKey: checksum(f().content?.content ?? ""),
|
||||
}}
|
||||
overflow="scroll"
|
||||
class="pb-40"
|
||||
/>
|
||||
@@ -606,41 +608,14 @@ export default function Page() {
|
||||
class="relative w-full flex flex-col shrink-0 border-t border-border-weak-base"
|
||||
style={{ height: `${layout.terminal.height()}px` }}
|
||||
>
|
||||
<div
|
||||
class="absolute inset-x-0 top-0 z-10 h-2 -translate-y-1/2 cursor-ns-resize"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault()
|
||||
const startY = e.clientY
|
||||
const startHeight = layout.terminal.height()
|
||||
const maxHeight = window.innerHeight * 0.6
|
||||
const minHeight = 100
|
||||
const collapseThreshold = 50
|
||||
let currentHeight = startHeight
|
||||
|
||||
document.body.style.userSelect = "none"
|
||||
document.body.style.overflow = "hidden"
|
||||
|
||||
const onMouseMove = (moveEvent: MouseEvent) => {
|
||||
const deltaY = startY - moveEvent.clientY
|
||||
currentHeight = startHeight + deltaY
|
||||
const clampedHeight = Math.min(maxHeight, Math.max(minHeight, currentHeight))
|
||||
layout.terminal.resize(clampedHeight)
|
||||
}
|
||||
|
||||
const onMouseUp = () => {
|
||||
document.body.style.userSelect = ""
|
||||
document.body.style.overflow = ""
|
||||
document.removeEventListener("mousemove", onMouseMove)
|
||||
document.removeEventListener("mouseup", onMouseUp)
|
||||
|
||||
if (currentHeight < collapseThreshold) {
|
||||
layout.terminal.close()
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("mousemove", onMouseMove)
|
||||
document.addEventListener("mouseup", onMouseUp)
|
||||
}}
|
||||
<ResizeHandle
|
||||
direction="vertical"
|
||||
size={layout.terminal.height()}
|
||||
min={100}
|
||||
max={window.innerHeight * 0.6}
|
||||
collapseThreshold={50}
|
||||
onResize={layout.terminal.resize}
|
||||
onCollapse={layout.terminal.close}
|
||||
/>
|
||||
<Tabs variant="alt" value={session.terminal.active()} onChange={session.terminal.open}>
|
||||
<Tabs.List class="h-10">
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
export function base64Encode(value: string) {
|
||||
return btoa(value).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "")
|
||||
}
|
||||
|
||||
export function base64Decode(value: string) {
|
||||
return atob(value.replace(/-/g, "+").replace(/_/g, "/"))
|
||||
}
|
||||
@@ -1,2 +1 @@
|
||||
export * from "./dom"
|
||||
export * from "./encode"
|
||||
|
||||
@@ -8,53 +8,20 @@
|
||||
"dark": "#15803D"
|
||||
},
|
||||
"favicon": "/favicon.svg",
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://opencode.ai/openapi.json"
|
||||
}
|
||||
],
|
||||
"navigation": {
|
||||
"tabs": [
|
||||
{
|
||||
"tab": "Guides",
|
||||
"tab": "SDK",
|
||||
"groups": [
|
||||
{
|
||||
"group": "Getting started",
|
||||
"pages": ["index", "quickstart", "development"]
|
||||
},
|
||||
{
|
||||
"group": "Customization",
|
||||
"pages": ["essentials/settings", "essentials/navigation"]
|
||||
},
|
||||
{
|
||||
"group": "Writing content",
|
||||
"pages": ["essentials/markdown", "essentials/code", "essentials/images", "essentials/reusable-snippets"]
|
||||
},
|
||||
{
|
||||
"group": "AI tools",
|
||||
"pages": ["ai-tools/cursor", "ai-tools/claude-code", "ai-tools/windsurf"]
|
||||
"pages": ["index", "quickstart", "development"],
|
||||
"openapi": "https://opencode.ai/openapi.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tab": "API Reference",
|
||||
"openapi": "https://opencode.ai/openapi.json"
|
||||
}
|
||||
],
|
||||
"global": {
|
||||
"anchors": [
|
||||
{
|
||||
"anchor": "Documentation",
|
||||
"href": "https://mintlify.com/docs",
|
||||
"icon": "book-open-cover"
|
||||
},
|
||||
{
|
||||
"anchor": "Blog",
|
||||
"href": "https://mintlify.com/blog",
|
||||
"icon": "newspaper"
|
||||
}
|
||||
]
|
||||
}
|
||||
"global": {}
|
||||
},
|
||||
"logo": {
|
||||
"light": "/logo/light.svg",
|
||||
|
||||
1
packages/docs/openapi.json
Symbolic link
@@ -0,0 +1 @@
|
||||
../sdk/openapi.json
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { FileDiff, Message, Model, Part, Session, SessionStatus, UserMessage } f
|
||||
import { SessionTurn } from "@opencode-ai/ui/session-turn"
|
||||
import { SessionReview } from "@opencode-ai/ui/session-review"
|
||||
import { DataProvider } from "@opencode-ai/ui/context"
|
||||
import { DiffComponentProvider } from "@opencode-ai/ui/context/diff"
|
||||
import { createAsync, query, useParams } from "@solidjs/router"
|
||||
import { createEffect, createMemo, ErrorBoundary, For, Match, Show, Switch } from "solid-js"
|
||||
import { Share } from "~/core/share"
|
||||
@@ -18,7 +19,7 @@ import z from "zod"
|
||||
import NotFound from "../[...404]"
|
||||
import { Tabs } from "@opencode-ai/ui/tabs"
|
||||
import { preloadMultiFileDiff, PreloadMultiFileDiffResult } from "@pierre/precision-diffs/ssr"
|
||||
import { Diff } from "@opencode-ai/ui/diff-ssr"
|
||||
import { Diff as SSRDiff } from "@opencode-ai/ui/diff-ssr"
|
||||
import { clientOnly } from "@solidjs/start"
|
||||
|
||||
const ClientOnlyDiff = clientOnly(() => import("@opencode-ai/ui/diff").then((m) => ({ default: m.Diff })))
|
||||
@@ -157,234 +158,240 @@ export default function () {
|
||||
const info = createMemo(() => data().session[match().index])
|
||||
|
||||
return (
|
||||
<DataProvider data={data()} directory={info().directory}>
|
||||
{iife(() => {
|
||||
const [store, setStore] = createStore({
|
||||
messageId: undefined as string | undefined,
|
||||
})
|
||||
const messages = createMemo(() =>
|
||||
data().sessionID
|
||||
? (data().message[data().sessionID]?.filter((m) => m.role === "user") ?? []).sort(
|
||||
(a, b) => b.time.created - a.time.created,
|
||||
)
|
||||
: [],
|
||||
)
|
||||
const firstUserMessage = createMemo(() => messages().at(0))
|
||||
const activeMessage = createMemo(
|
||||
() => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(),
|
||||
)
|
||||
function setActiveMessage(message: UserMessage | undefined) {
|
||||
if (message) {
|
||||
setStore("messageId", message.id)
|
||||
} else {
|
||||
setStore("messageId", undefined)
|
||||
<DiffComponentProvider component={ClientOnlyDiff}>
|
||||
<DataProvider data={data()} directory={info().directory}>
|
||||
{iife(() => {
|
||||
const [store, setStore] = createStore({
|
||||
messageId: undefined as string | undefined,
|
||||
})
|
||||
const messages = createMemo(() =>
|
||||
data().sessionID
|
||||
? (data().message[data().sessionID]?.filter((m) => m.role === "user") ?? []).sort(
|
||||
(a, b) => b.time.created - a.time.created,
|
||||
)
|
||||
: [],
|
||||
)
|
||||
const firstUserMessage = createMemo(() => messages().at(0))
|
||||
const activeMessage = createMemo(
|
||||
() => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(),
|
||||
)
|
||||
function setActiveMessage(message: UserMessage | undefined) {
|
||||
if (message) {
|
||||
setStore("messageId", message.id)
|
||||
} else {
|
||||
setStore("messageId", undefined)
|
||||
}
|
||||
}
|
||||
}
|
||||
const provider = createMemo(() => activeMessage()?.model?.providerID)
|
||||
const modelID = createMemo(() => activeMessage()?.model?.modelID)
|
||||
const model = createMemo(() => data().model[data().sessionID]?.find((m) => m.id === modelID()))
|
||||
const diffs = createMemo(() => {
|
||||
const diffs = data().session_diff[data().sessionID] ?? []
|
||||
const preloaded = data().session_diff_preload[data().sessionID] ?? []
|
||||
return diffs.map((diff) => ({
|
||||
...diff,
|
||||
preloaded: preloaded.find((d) => d.newFile.name === diff.file),
|
||||
}))
|
||||
})
|
||||
const splitDiffs = createMemo(() => {
|
||||
const diffs = data().session_diff[data().sessionID] ?? []
|
||||
const preloaded = data().session_diff_preload_split[data().sessionID] ?? []
|
||||
return diffs.map((diff) => ({
|
||||
...diff,
|
||||
preloaded: preloaded.find((d) => d.newFile.name === diff.file),
|
||||
}))
|
||||
})
|
||||
const provider = createMemo(() => activeMessage()?.model?.providerID)
|
||||
const modelID = createMemo(() => activeMessage()?.model?.modelID)
|
||||
const model = createMemo(() => data().model[data().sessionID]?.find((m) => m.id === modelID()))
|
||||
const diffs = createMemo(() => {
|
||||
const diffs = data().session_diff[data().sessionID] ?? []
|
||||
const preloaded = data().session_diff_preload[data().sessionID] ?? []
|
||||
return diffs.map((diff) => ({
|
||||
...diff,
|
||||
preloaded: preloaded.find((d) => d.newFile.name === diff.file),
|
||||
}))
|
||||
})
|
||||
const splitDiffs = createMemo(() => {
|
||||
const diffs = data().session_diff[data().sessionID] ?? []
|
||||
const preloaded = data().session_diff_preload_split[data().sessionID] ?? []
|
||||
return diffs.map((diff) => ({
|
||||
...diff,
|
||||
preloaded: preloaded.find((d) => d.newFile.name === diff.file),
|
||||
}))
|
||||
})
|
||||
|
||||
const title = () => (
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="h-8 flex gap-4 items-center justify-start self-stretch">
|
||||
<div class="pl-[2.5px] pr-2 flex items-center gap-1.75 bg-surface-strong shadow-xs-border-base">
|
||||
<Mark class="shrink-0 w-3 my-0.5" />
|
||||
<div class="text-12-mono text-text-base">v{info().version}</div>
|
||||
</div>
|
||||
<div class="flex gap-2 items-center">
|
||||
<img src={`https://models.dev/logos/${provider()}.svg`} class="size-3.5 shrink-0 dark:invert" />
|
||||
<div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div>
|
||||
</div>
|
||||
<div class="text-12-regular text-text-weaker">
|
||||
{DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-left text-16-medium text-text-strong">{info().title}</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const turns = () => (
|
||||
<div class="relative mt-2 pt-6 pb-8 min-w-0 w-full h-full overflow-y-auto no-scrollbar">
|
||||
<div class="px-4">{title()}</div>
|
||||
<div class="flex flex-col gap-15 items-start justify-start mt-4">
|
||||
<For each={messages()}>
|
||||
{(message) => (
|
||||
<SessionTurn
|
||||
sessionID={data().sessionID}
|
||||
messageID={message.id}
|
||||
classes={{
|
||||
root: "min-w-0 w-full relative",
|
||||
content:
|
||||
"flex flex-col justify-between !overflow-visible [&_[data-slot=session-turn-message-header]]:top-[-32px]",
|
||||
container: "px-4",
|
||||
}}
|
||||
diffComponent={ClientOnlyDiff}
|
||||
const title = () => (
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="h-8 flex gap-4 items-center justify-start self-stretch">
|
||||
<div class="pl-[2.5px] pr-2 flex items-center gap-1.75 bg-surface-strong shadow-xs-border-base">
|
||||
<Mark class="shrink-0 w-3 my-0.5" />
|
||||
<div class="text-12-mono text-text-base">v{info().version}</div>
|
||||
</div>
|
||||
<div class="flex gap-2 items-center">
|
||||
<img
|
||||
src={`https://models.dev/logos/${provider()}.svg`}
|
||||
class="size-3.5 shrink-0 dark:invert"
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
<div class="px-4 flex items-center justify-center pt-20 pb-8 shrink-0">
|
||||
<Logo class="w-58.5 opacity-12" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const wide = createMemo(() => diffs().length === 0)
|
||||
|
||||
return (
|
||||
<div class="relative bg-background-stronger w-screen h-screen overflow-hidden flex flex-col">
|
||||
<header class="h-12 px-6 py-2 flex items-center justify-between self-stretch bg-background-base border-b border-border-weak-base">
|
||||
<div class="">
|
||||
<a href="https://opencode.ai">
|
||||
<Mark />
|
||||
</a>
|
||||
<div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div>
|
||||
</div>
|
||||
<div class="text-12-regular text-text-weaker">
|
||||
{DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-3 items-center">
|
||||
<IconButton
|
||||
as={"a"}
|
||||
href="https://github.com/sst/opencode"
|
||||
target="_blank"
|
||||
icon="github"
|
||||
variant="ghost"
|
||||
/>
|
||||
<IconButton
|
||||
as={"a"}
|
||||
href="https://opencode.ai/discord"
|
||||
target="_blank"
|
||||
icon="discord"
|
||||
variant="ghost"
|
||||
/>
|
||||
<div class="text-left text-16-medium text-text-strong">{info().title}</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const turns = () => (
|
||||
<div class="relative mt-2 pt-6 pb-8 min-w-0 w-full h-full overflow-y-auto no-scrollbar">
|
||||
<div class="px-4">{title()}</div>
|
||||
<div class="flex flex-col gap-15 items-start justify-start mt-4">
|
||||
<For each={messages()}>
|
||||
{(message) => (
|
||||
<SessionTurn
|
||||
sessionID={data().sessionID}
|
||||
messageID={message.id}
|
||||
classes={{
|
||||
root: "min-w-0 w-full relative",
|
||||
content:
|
||||
"flex flex-col justify-between !overflow-visible [&_[data-slot=session-turn-message-header]]:top-[-32px]",
|
||||
container: "px-4",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</header>
|
||||
<div class="select-text flex flex-col flex-1 min-h-0">
|
||||
<div classList={{ "hidden w-full flex-1 min-h-0": true, "md:flex": wide(), "lg:flex": !wide() }}>
|
||||
<div class="px-4 flex items-center justify-center pt-20 pb-8 shrink-0">
|
||||
<Logo class="w-58.5 opacity-12" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const wide = createMemo(() => diffs().length === 0)
|
||||
|
||||
return (
|
||||
<div class="relative bg-background-stronger w-screen h-screen overflow-hidden flex flex-col">
|
||||
<header class="h-12 px-6 py-2 flex items-center justify-between self-stretch bg-background-base border-b border-border-weak-base">
|
||||
<div class="">
|
||||
<a href="https://opencode.ai">
|
||||
<Mark />
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex gap-3 items-center">
|
||||
<IconButton
|
||||
as={"a"}
|
||||
href="https://github.com/sst/opencode"
|
||||
target="_blank"
|
||||
icon="github"
|
||||
variant="ghost"
|
||||
/>
|
||||
<IconButton
|
||||
as={"a"}
|
||||
href="https://opencode.ai/discord"
|
||||
target="_blank"
|
||||
icon="discord"
|
||||
variant="ghost"
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
<div class="select-text flex flex-col flex-1 min-h-0">
|
||||
<div
|
||||
classList={{
|
||||
"@container relative shrink-0 pt-14 flex flex-col gap-10 min-h-0 w-full": true,
|
||||
"mx-auto max-w-146": !wide(),
|
||||
}}
|
||||
classList={{ "hidden w-full flex-1 min-h-0": true, "md:flex": wide(), "lg:flex": !wide() }}
|
||||
>
|
||||
<div
|
||||
classList={{
|
||||
"w-full flex justify-start items-start min-w-0": true,
|
||||
"max-w-146 mx-auto px-6": wide(),
|
||||
"pr-6 pl-18": !wide() && messages().length > 1,
|
||||
"px-6": !wide() && messages().length === 1,
|
||||
"@container relative shrink-0 pt-14 flex flex-col gap-10 min-h-0 w-full": true,
|
||||
"mx-auto max-w-146": !wide(),
|
||||
}}
|
||||
>
|
||||
{title()}
|
||||
</div>
|
||||
<div class="flex items-start justify-start h-full min-h-0">
|
||||
<SessionMessageRail
|
||||
messages={messages()}
|
||||
current={activeMessage()}
|
||||
onMessageSelect={setActiveMessage}
|
||||
wide={wide()}
|
||||
/>
|
||||
<SessionTurn
|
||||
sessionID={data().sessionID}
|
||||
messageID={store.messageId ?? firstUserMessage()!.id!}
|
||||
classes={{
|
||||
root: "grow",
|
||||
content: "flex flex-col justify-between items-start",
|
||||
container:
|
||||
"w-full pb-20 " +
|
||||
(wide() ? "max-w-146 mx-auto px-6" : messages().length > 1 ? "pr-6 pl-18" : "px-6"),
|
||||
<div
|
||||
classList={{
|
||||
"w-full flex justify-start items-start min-w-0": true,
|
||||
"max-w-146 mx-auto px-6": wide(),
|
||||
"pr-6 pl-18": !wide() && messages().length > 1,
|
||||
"px-6": !wide() && messages().length === 1,
|
||||
}}
|
||||
diffComponent={ClientOnlyDiff}
|
||||
>
|
||||
<div classList={{ "w-full flex items-center justify-center pb-8 shrink-0": true }}>
|
||||
<Logo class="w-58.5 opacity-12" />
|
||||
</div>
|
||||
</SessionTurn>
|
||||
{title()}
|
||||
</div>
|
||||
<div class="flex items-start justify-start h-full min-h-0">
|
||||
<SessionMessageRail
|
||||
messages={messages()}
|
||||
current={activeMessage()}
|
||||
onMessageSelect={setActiveMessage}
|
||||
wide={wide()}
|
||||
/>
|
||||
<SessionTurn
|
||||
sessionID={data().sessionID}
|
||||
messageID={store.messageId ?? firstUserMessage()!.id!}
|
||||
classes={{
|
||||
root: "grow",
|
||||
content: "flex flex-col justify-between items-start",
|
||||
container:
|
||||
"w-full pb-20 " +
|
||||
(wide() ? "max-w-146 mx-auto px-6" : messages().length > 1 ? "pr-6 pl-18" : "px-6"),
|
||||
}}
|
||||
>
|
||||
<div classList={{ "w-full flex items-center justify-center pb-8 shrink-0": true }}>
|
||||
<Logo class="w-58.5 opacity-12" />
|
||||
</div>
|
||||
</SessionTurn>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Show when={diffs().length > 0}>
|
||||
<div class="@container relative grow pt-14 flex-1 min-h-0 border-l border-border-weak-base">
|
||||
<SessionReview
|
||||
class="@4xl:hidden"
|
||||
diffs={diffs()}
|
||||
diffComponent={Diff}
|
||||
classes={{
|
||||
root: "pb-20",
|
||||
header: "px-6",
|
||||
container: "px-6",
|
||||
}}
|
||||
/>
|
||||
<SessionReview
|
||||
split
|
||||
class="hidden @4xl:flex"
|
||||
diffs={splitDiffs()}
|
||||
diffComponent={Diff}
|
||||
classes={{
|
||||
root: "pb-20",
|
||||
header: "px-6",
|
||||
container: "px-6",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
<Switch>
|
||||
<Match when={diffs().length > 0}>
|
||||
<Tabs classList={{ "md:hidden": wide(), "lg:hidden": !wide() }}>
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="session" class="w-1/2" classes={{ button: "w-full" }}>
|
||||
Session
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="review" class="w-1/2 !border-r-0" classes={{ button: "w-full" }}>
|
||||
5 Files Changed
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<Tabs.Content value="session" class="!overflow-hidden">
|
||||
{turns()}
|
||||
</Tabs.Content>
|
||||
<Tabs.Content
|
||||
forceMount
|
||||
value="review"
|
||||
class="!overflow-hidden hidden data-[selected]:block"
|
||||
>
|
||||
<div class="relative h-full pt-8 overflow-y-auto no-scrollbar">
|
||||
<Show when={diffs().length > 0}>
|
||||
<DiffComponentProvider component={SSRDiff}>
|
||||
<div class="@container relative grow pt-14 flex-1 min-h-0 border-l border-border-weak-base">
|
||||
<SessionReview
|
||||
class="@4xl:hidden"
|
||||
diffs={diffs()}
|
||||
diffComponent={Diff}
|
||||
classes={{
|
||||
root: "pb-20",
|
||||
header: "px-4",
|
||||
container: "px-4",
|
||||
header: "px-6",
|
||||
container: "px-6",
|
||||
}}
|
||||
/>
|
||||
<SessionReview
|
||||
split
|
||||
class="hidden @4xl:flex"
|
||||
diffs={splitDiffs()}
|
||||
classes={{
|
||||
root: "pb-20",
|
||||
header: "px-6",
|
||||
container: "px-6",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
</Tabs>
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<div classList={{ "!overflow-hidden": true, "md:hidden": wide(), "lg:hidden": !wide() }}>
|
||||
{turns()}
|
||||
</div>
|
||||
</Match>
|
||||
</Switch>
|
||||
</DiffComponentProvider>
|
||||
</Show>
|
||||
</div>
|
||||
<Switch>
|
||||
<Match when={diffs().length > 0}>
|
||||
<Tabs classList={{ "md:hidden": wide(), "lg:hidden": !wide() }}>
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="session" class="w-1/2" classes={{ button: "w-full" }}>
|
||||
Session
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="review" class="w-1/2 !border-r-0" classes={{ button: "w-full" }}>
|
||||
{diffs().length} Files Changed
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<Tabs.Content value="session" class="!overflow-hidden">
|
||||
{turns()}
|
||||
</Tabs.Content>
|
||||
<Tabs.Content
|
||||
forceMount
|
||||
value="review"
|
||||
class="!overflow-hidden hidden data-[selected]:block"
|
||||
>
|
||||
<div class="relative h-full pt-8 overflow-y-auto no-scrollbar">
|
||||
<DiffComponentProvider component={SSRDiff}>
|
||||
<SessionReview
|
||||
diffs={diffs()}
|
||||
classes={{
|
||||
root: "pb-20",
|
||||
header: "px-4",
|
||||
container: "px-4",
|
||||
}}
|
||||
/>
|
||||
</DiffComponentProvider>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
</Tabs>
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<div classList={{ "!overflow-hidden": true, "md:hidden": wide(), "lg:hidden": !wide() }}>
|
||||
{turns()}
|
||||
</div>
|
||||
</Match>
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</DataProvider>
|
||||
)
|
||||
})}
|
||||
</DataProvider>
|
||||
</DiffComponentProvider>
|
||||
)
|
||||
}}
|
||||
</Show>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
id = "opencode"
|
||||
name = "OpenCode"
|
||||
description = "The AI coding agent built for the terminal"
|
||||
version = "1.0.134"
|
||||
description = "The open source coding agent."
|
||||
version = "1.0.137"
|
||||
schema_version = 1
|
||||
authors = ["Anomaly"]
|
||||
repository = "https://github.com/sst/opencode"
|
||||
@@ -11,26 +11,26 @@ name = "OpenCode"
|
||||
icon = "./icons/opencode.svg"
|
||||
|
||||
[agent_servers.opencode.targets.darwin-aarch64]
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.134/opencode-darwin-arm64.zip"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.137/opencode-darwin-arm64.zip"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.darwin-x86_64]
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.134/opencode-darwin-x64.zip"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.137/opencode-darwin-x64.zip"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.linux-aarch64]
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.134/opencode-linux-arm64.zip"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.137/opencode-linux-arm64.tar.gz"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.linux-x86_64]
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.134/opencode-linux-x64.zip"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.137/opencode-linux-x64.tar.gz"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.windows-x86_64]
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.134/opencode-windows-x64.zip"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.137/opencode-windows-x64.zip"
|
||||
cmd = "./opencode.exe"
|
||||
args = ["acp"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/function",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
@@ -1,12 +0,0 @@
|
||||
<svg width="289" height="50" viewBox="0 0 289 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M264.5 0H288.5V8.5H272.5V16.5H288.5V25H272.5V33H288.5V41.5H264.5V0Z" fill="white"/>
|
||||
<path d="M248.5 0H224.5V41.5H248.5V33H232.5V8.5H248.5V0Z" fill="white"/>
|
||||
<path d="M256.5 8.5H248.5V33H256.5V8.5Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M184.5 0H216.5V41.5H184.5V0ZM208.5 8.5H192.5V33H208.5V8.5Z" fill="white"/>
|
||||
<path d="M144.5 8.5H136.5V41.5H144.5V8.5Z" fill="white"/>
|
||||
<path d="M136.5 0H112.5V41.5H120.5V8.5H136.5V0Z" fill="white"/>
|
||||
<path d="M80.5 0H104.5V8.5H88.5V16.5H104.5V25H88.5V33H104.5V41.5H80.5V0Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M40.5 0H72.5V41.5H48.5V49.5H40.5V0ZM64.5 8.5H48.5V33H64.5V8.5Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.5 0H32.5V41.5955H0.5V0ZM24.5 8.5H8.5V33H24.5V8.5Z" fill="white"/>
|
||||
<path d="M152.5 0H176.5V8.5H160.5V33H176.5V41.5H152.5V0Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 981 B |
@@ -1,12 +0,0 @@
|
||||
<svg width="289" height="50" viewBox="0 0 289 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M264.5 0H288.5V8.5H272.5V16.5H288.5V25H272.5V33H288.5V41.5H264.5V0Z" fill="black"/>
|
||||
<path d="M248.5 0H224.5V41.5H248.5V33H232.5V8.5H248.5V0Z" fill="black"/>
|
||||
<path d="M256.5 8.5H248.5V33H256.5V8.5Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M184.5 0H216.5V41.5H184.5V0ZM208.5 8.5H192.5V33H208.5V8.5Z" fill="black"/>
|
||||
<path d="M144.5 8.5H136.5V41.5H144.5V8.5Z" fill="black"/>
|
||||
<path d="M136.5 0H112.5V41.5H120.5V8.5H136.5V0Z" fill="black"/>
|
||||
<path d="M80.5 0H104.5V8.5H88.5V16.5H104.5V25H88.5V33H104.5V41.5H80.5V0Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M40.5 0H72.5V41.5H48.5V49.5H40.5V0ZM64.5 8.5H48.5V33H64.5V8.5Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.5 0H32.5V41.5955H0.5V0ZM24.5 8.5H8.5V33H24.5V8.5Z" fill="black"/>
|
||||
<path d="M152.5 0H176.5V8.5H160.5V33H176.5V41.5H152.5V0Z" fill="black"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 981 B |
@@ -1,18 +0,0 @@
|
||||
<svg width="289" height="50" viewBox="0 0 289 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.5 16.5H24.5V33H8.5V16.5Z" fill="white" fill-opacity="0.2"/>
|
||||
<path d="M48.5 16.5H64.5V33H48.5V16.5Z" fill="white" fill-opacity="0.2"/>
|
||||
<path d="M120.5 16.5H136.5V33H120.5V16.5Z" fill="white" fill-opacity="0.2"/>
|
||||
<path d="M160.5 16.5H176.5V33H160.5V16.5Z" fill="white" fill-opacity="0.2"/>
|
||||
<path d="M192.5 16.5H208.5V33H192.5V16.5Z" fill="white" fill-opacity="0.2"/>
|
||||
<path d="M232.5 16.5H248.5V33H232.5V16.5Z" fill="white" fill-opacity="0.2"/>
|
||||
<path d="M264.5 0H288.5V8.5H272.5V16.5H288.5V25H272.5V33H288.5V41.5H264.5V0Z" fill="white" fill-opacity="0.95"/>
|
||||
<path d="M248.5 0H224.5V41.5H248.5V33H232.5V8.5H248.5V0Z" fill="white" fill-opacity="0.95"/>
|
||||
<path d="M256.5 8.5H248.5V33H256.5V8.5Z" fill="white" fill-opacity="0.95"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M184.5 0H216.5V41.5H184.5V0ZM208.5 8.5H192.5V33H208.5V8.5Z" fill="white" fill-opacity="0.95"/>
|
||||
<path d="M144.5 8.5H136.5V41.5H144.5V8.5Z" fill="white" fill-opacity="0.5"/>
|
||||
<path d="M136.5 0H112.5V41.5H120.5V8.5H136.5V0Z" fill="white" fill-opacity="0.5"/>
|
||||
<path d="M80.5 0H104.5V8.5H88.5V16.5H104.5V25H88.5V33H104.5V41.5H80.5V0Z" fill="white" fill-opacity="0.5"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M40.5 0H72.5V41.5H48.5V49.5H40.5V0ZM64.5 8.5H48.5V33H64.5V8.5Z" fill="white" fill-opacity="0.5"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.5 0H32.5V41.5955H0.5V0ZM24.5 8.5H8.5V33H24.5V8.5Z" fill="white" fill-opacity="0.5"/>
|
||||
<path d="M152.5 0H176.5V8.5H160.5V33H176.5V41.5H152.5V0Z" fill="white" fill-opacity="0.95"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -1,18 +0,0 @@
|
||||
<svg width="288" height="50" viewBox="0 0 288 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 16.5H24V33H8V16.5Z" fill="black" fill-opacity="0.15"/>
|
||||
<path d="M48 16.5H64V33H48V16.5Z" fill="black" fill-opacity="0.15"/>
|
||||
<path d="M120 16.5H136V33H120V16.5Z" fill="black" fill-opacity="0.15"/>
|
||||
<path d="M160 16.5H176V33H160V16.5Z" fill="black" fill-opacity="0.15"/>
|
||||
<path d="M192 16.5H208V33H192V16.5Z" fill="black" fill-opacity="0.15"/>
|
||||
<path d="M232 16.5H248V33H232V16.5Z" fill="black" fill-opacity="0.15"/>
|
||||
<path d="M264 0H288V8.5H272V16.5H288V25H272V33H288V41.5H264V0Z" fill="black" fill-opacity="0.95"/>
|
||||
<path d="M248 0H224V41.5H248V33H232V8.5H248V0Z" fill="black" fill-opacity="0.95"/>
|
||||
<path d="M256 8.5H248V33H256V8.5Z" fill="black" fill-opacity="0.95"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M184 0H216V41.5H184V0ZM208 8.5H192V33H208V8.5Z" fill="black" fill-opacity="0.95"/>
|
||||
<path d="M144 8.5H136V41.5H144V8.5Z" fill="black" fill-opacity="0.55"/>
|
||||
<path d="M136 0H112V41.5H120V8.5H136V0Z" fill="black" fill-opacity="0.55"/>
|
||||
<path d="M80 0H104V8.5H88V16.5H104V25H88V33H104V41.5H80V0Z" fill="black" fill-opacity="0.55"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M40 0H72V41.5H48V49.5H40V0ZM64 8.5H48V33H64V8.5Z" fill="black" fill-opacity="0.55"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0H32V41.5955H0V0ZM24 8.5H8V33H24V8.5Z" fill="black" fill-opacity="0.55"/>
|
||||
<path d="M152 0H176V8.5H160V33H176V41.5H152V0Z" fill="black" fill-opacity="0.95"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,4 +0,0 @@
|
||||
<svg width="70" height="70" viewBox="0 0 70 70" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 13H35V58H0V13ZM26.25 22.1957H8.75V48.701H26.25V22.1957Z" fill="white"/>
|
||||
<path d="M43.75 13H70V22.1957H52.5V48.701H70V57.8967H43.75V13Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 306 B |
@@ -1,4 +0,0 @@
|
||||
<svg width="70" height="70" viewBox="0 0 70 70" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 13H35V58H0V13ZM26.25 22.1957H8.75V48.701H26.25V22.1957Z" fill="black"/>
|
||||
<path d="M43.75 13H70V22.1957H52.5V48.701H70V57.8967H43.75V13Z" fill="black"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 306 B |
@@ -1,4 +0,0 @@
|
||||
<svg width="64" height="42" viewBox="0 0 64 42" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0H32V41.5955H0V0ZM24 8.5H8V33H24V8.5Z" fill="white"/>
|
||||
<path d="M40 0H64V8.5H48V33H64V41.5H40V0Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 267 B |
@@ -1,4 +0,0 @@
|
||||
<svg width="64" height="42" viewBox="0 0 64 42" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0H32V41.5955H0V0ZM24 8.5H8V33H24V8.5Z" fill="black"/>
|
||||
<path d="M40 0H64V8.5H48V33H64V41.5H40V0Z" fill="black"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 267 B |
BIN
packages/identity/mark-192x192.png
Normal file
|
After Width: | Height: | Size: 144 B |
BIN
packages/identity/mark-512x512-light.png
Normal file
|
After Width: | Height: | Size: 330 B |
BIN
packages/identity/mark-512x512.png
Normal file
|
After Width: | Height: | Size: 330 B |
BIN
packages/identity/mark-96x96.png
Normal file
|
After Width: | Height: | Size: 122 B |
5
packages/identity/mark-light.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="512" height="512" fill="#FDFCFC"/>
|
||||
<path d="M320 224V352H192V224H320Z" fill="#E6E5E6"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M384 416H128V96H384V416ZM320 160H192V352H320V160Z" fill="#17181C"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 325 B |
7
packages/identity/mark.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512"><svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="512" height="512" fill="#131010"></rect>
|
||||
<path d="M320 224V352H192V224H320Z" fill="#5A5858"></path>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M384 416H128V96H384V416ZM320 160H192V352H320V160Z" fill="white"></path>
|
||||
</svg><style>@media (prefers-color-scheme: light) { :root { filter: none; } }
|
||||
@media (prefers-color-scheme: dark) { :root { filter: none; } }
|
||||
</style></svg>
|
||||
|
After Width: | Height: | Size: 612 B |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.0.134",
|
||||
"version": "1.0.137",
|
||||
"name": "opencode",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
@@ -23,7 +23,9 @@
|
||||
"@parcel/watcher-darwin-arm64": "2.5.1",
|
||||
"@parcel/watcher-darwin-x64": "2.5.1",
|
||||
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-arm64-musl": "2.5.1",
|
||||
"@parcel/watcher-linux-x64-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-x64-musl": "2.5.1",
|
||||
"@parcel/watcher-win32-x64": "2.5.1",
|
||||
"@standard-schema/spec": "1.0.0",
|
||||
"@tsconfig/bun": "catalog:",
|
||||
@@ -64,8 +66,8 @@
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@opencode-ai/util": "workspace:*",
|
||||
"@openrouter/ai-sdk-provider": "1.2.8",
|
||||
"@opentui/core": "0.1.56",
|
||||
"@opentui/solid": "0.1.56",
|
||||
"@opentui/core": "0.1.59",
|
||||
"@opentui/solid": "0.1.59",
|
||||
"@parcel/watcher": "2.5.1",
|
||||
"@pierre/precision-diffs": "catalog:",
|
||||
"@solid-primitives/event-bus": "1.1.2",
|
||||
|
||||
@@ -128,6 +128,7 @@ for (const item of targets) {
|
||||
OTUI_TREE_SITTER_WORKER_PATH: bunfsRoot + workerRelativePath,
|
||||
OPENCODE_WORKER_PATH: workerPath,
|
||||
OPENCODE_CHANNEL: `'${Script.channel}'`,
|
||||
OPENCODE_LIBC: item.os === "linux" ? `'${item.abi ?? "glibc"}'` : "",
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -199,6 +199,8 @@ if (!Script.preview) {
|
||||
` homepage "https://github.com/sst/opencode"`,
|
||||
` version "${Script.version.split("-")[0]}"`,
|
||||
"",
|
||||
` depends_on "ripgrep"`,
|
||||
"",
|
||||
" on_macos do",
|
||||
" if Hardware::CPU.intel?",
|
||||
` url "https://github.com/sst/opencode/releases/download/v${Script.version}/opencode-darwin-x64.zip"`,
|
||||
|
||||
@@ -29,7 +29,7 @@ import { MCP } from "@/mcp"
|
||||
import { Todo } from "@/session/todo"
|
||||
import { z } from "zod"
|
||||
import { LoadAPIKeyError } from "ai"
|
||||
import type { OpencodeClient } from "@opencode-ai/sdk"
|
||||
import type { OpencodeClient } from "@opencode-ai/sdk/v2"
|
||||
|
||||
export namespace ACP {
|
||||
const log = Log.create({ service: "acp-agent" })
|
||||
@@ -68,7 +68,7 @@ export namespace ACP {
|
||||
{ optionId: "always", kind: "allow_always", name: "Always allow" },
|
||||
{ optionId: "reject", kind: "reject_once", name: "Reject" },
|
||||
]
|
||||
this.config.sdk.event.subscribe({ query: { directory } }).then(async (events) => {
|
||||
this.config.sdk.event.subscribe({ directory }).then(async (events) => {
|
||||
for await (const event of events.stream) {
|
||||
switch (event.type) {
|
||||
case "permission.updated":
|
||||
@@ -93,32 +93,29 @@ export namespace ACP {
|
||||
permissionID: permission.id,
|
||||
sessionID: permission.sessionID,
|
||||
})
|
||||
await this.config.sdk.postSessionIdPermissionsPermissionId({
|
||||
path: { id: permission.sessionID, permissionID: permission.id },
|
||||
body: {
|
||||
response: "reject",
|
||||
},
|
||||
query: { directory },
|
||||
await this.config.sdk.permission.respond({
|
||||
sessionID: permission.sessionID,
|
||||
permissionID: permission.id,
|
||||
response: "reject",
|
||||
directory,
|
||||
})
|
||||
return
|
||||
})
|
||||
if (!res) return
|
||||
if (res.outcome.outcome !== "selected") {
|
||||
await this.config.sdk.postSessionIdPermissionsPermissionId({
|
||||
path: { id: permission.sessionID, permissionID: permission.id },
|
||||
body: {
|
||||
response: "reject",
|
||||
},
|
||||
query: { directory },
|
||||
await this.config.sdk.permission.respond({
|
||||
sessionID: permission.sessionID,
|
||||
permissionID: permission.id,
|
||||
response: "reject",
|
||||
directory,
|
||||
})
|
||||
return
|
||||
}
|
||||
await this.config.sdk.postSessionIdPermissionsPermissionId({
|
||||
path: { id: permission.sessionID, permissionID: permission.id },
|
||||
body: {
|
||||
response: res.outcome.optionId as "once" | "always" | "reject",
|
||||
},
|
||||
query: { directory },
|
||||
await this.config.sdk.permission.respond({
|
||||
sessionID: permission.sessionID,
|
||||
permissionID: permission.id,
|
||||
response: res.outcome.optionId as "once" | "always" | "reject",
|
||||
directory,
|
||||
})
|
||||
} catch (err) {
|
||||
log.error("unexpected error when handling permission", { error: err })
|
||||
@@ -133,14 +130,14 @@ export namespace ACP {
|
||||
const { part } = props
|
||||
|
||||
const message = await this.config.sdk.session
|
||||
.message({
|
||||
throwOnError: true,
|
||||
path: {
|
||||
id: part.sessionID,
|
||||
.message(
|
||||
{
|
||||
sessionID: part.sessionID,
|
||||
messageID: part.messageID,
|
||||
directory,
|
||||
},
|
||||
query: { directory },
|
||||
})
|
||||
{ throwOnError: true },
|
||||
)
|
||||
.then((x) => x.data)
|
||||
.catch((err) => {
|
||||
log.error("unexpected error when fetching message", { error: err })
|
||||
@@ -420,9 +417,7 @@ export namespace ACP {
|
||||
const model = await defaultModel(this.config, directory)
|
||||
const sessionId = params.sessionId
|
||||
|
||||
const providers = await this.sdk.config
|
||||
.providers({ throwOnError: true, query: { directory } })
|
||||
.then((x) => x.data.providers)
|
||||
const providers = await this.sdk.config.providers({ directory }).then((x) => x.data!.providers)
|
||||
const entries = providers.sort((a, b) => {
|
||||
const nameA = a.name.toLowerCase()
|
||||
const nameB = b.name.toLowerCase()
|
||||
@@ -439,22 +434,22 @@ export namespace ACP {
|
||||
})
|
||||
|
||||
const agents = await this.config.sdk.app
|
||||
.agents({
|
||||
throwOnError: true,
|
||||
query: {
|
||||
.agents(
|
||||
{
|
||||
directory,
|
||||
},
|
||||
})
|
||||
.then((resp) => resp.data)
|
||||
{ throwOnError: true },
|
||||
)
|
||||
.then((resp) => resp.data!)
|
||||
|
||||
const commands = await this.config.sdk.command
|
||||
.list({
|
||||
throwOnError: true,
|
||||
query: {
|
||||
.list(
|
||||
{
|
||||
directory,
|
||||
},
|
||||
})
|
||||
.then((resp) => resp.data)
|
||||
{ throwOnError: true },
|
||||
)
|
||||
.then((resp) => resp.data!)
|
||||
|
||||
const availableCommands = commands.map((command) => ({
|
||||
name: command.name,
|
||||
@@ -503,14 +498,14 @@ export namespace ACP {
|
||||
await Promise.all(
|
||||
Object.entries(mcpServers).map(async ([key, mcp]) => {
|
||||
await this.sdk.mcp
|
||||
.add({
|
||||
throwOnError: true,
|
||||
query: { directory },
|
||||
body: {
|
||||
.add(
|
||||
{
|
||||
directory,
|
||||
name: key,
|
||||
config: mcp,
|
||||
},
|
||||
})
|
||||
{ throwOnError: true },
|
||||
)
|
||||
.catch((error) => {
|
||||
log.error("failed to add mcp server", { name: key, error })
|
||||
})
|
||||
@@ -559,7 +554,7 @@ export namespace ACP {
|
||||
async setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse | void> {
|
||||
this.sessionManager.get(params.sessionId)
|
||||
await this.config.sdk.app
|
||||
.agents({ throwOnError: true })
|
||||
.agents({}, { throwOnError: true })
|
||||
.then((x) => x.data)
|
||||
.then((agent) => {
|
||||
if (!agent) throw new Error(`Agent not found: ${params.modeId}`)
|
||||
@@ -651,50 +646,42 @@ export namespace ACP {
|
||||
|
||||
if (!cmd) {
|
||||
await this.sdk.session.prompt({
|
||||
path: { id: sessionID },
|
||||
body: {
|
||||
model: {
|
||||
providerID: model.providerID,
|
||||
modelID: model.modelID,
|
||||
},
|
||||
parts,
|
||||
agent,
|
||||
},
|
||||
query: {
|
||||
directory,
|
||||
sessionID,
|
||||
model: {
|
||||
providerID: model.providerID,
|
||||
modelID: model.modelID,
|
||||
},
|
||||
parts,
|
||||
agent,
|
||||
directory,
|
||||
})
|
||||
return done
|
||||
}
|
||||
|
||||
const command = await this.config.sdk.command
|
||||
.list({ throwOnError: true, query: { directory } })
|
||||
.then((x) => x.data.find((c) => c.name === cmd.name))
|
||||
.list({ directory }, { throwOnError: true })
|
||||
.then((x) => x.data!.find((c) => c.name === cmd.name))
|
||||
if (command) {
|
||||
await this.sdk.session.command({
|
||||
path: { id: sessionID },
|
||||
body: {
|
||||
command: command.name,
|
||||
arguments: cmd.args,
|
||||
model: model.providerID + "/" + model.modelID,
|
||||
agent,
|
||||
},
|
||||
query: {
|
||||
directory,
|
||||
},
|
||||
sessionID,
|
||||
command: command.name,
|
||||
arguments: cmd.args,
|
||||
model: model.providerID + "/" + model.modelID,
|
||||
agent,
|
||||
directory,
|
||||
})
|
||||
return done
|
||||
}
|
||||
|
||||
switch (cmd.name) {
|
||||
case "compact":
|
||||
await this.config.sdk.session.summarize({
|
||||
path: { id: sessionID },
|
||||
throwOnError: true,
|
||||
query: {
|
||||
await this.config.sdk.session.summarize(
|
||||
{
|
||||
sessionID,
|
||||
directory,
|
||||
},
|
||||
})
|
||||
{ throwOnError: true },
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
@@ -703,13 +690,13 @@ export namespace ACP {
|
||||
|
||||
async cancel(params: CancelNotification) {
|
||||
const session = this.sessionManager.get(params.sessionId)
|
||||
await this.config.sdk.session.abort({
|
||||
path: { id: params.sessionId },
|
||||
throwOnError: true,
|
||||
query: {
|
||||
await this.config.sdk.session.abort(
|
||||
{
|
||||
sessionID: params.sessionId,
|
||||
directory: session.cwd,
|
||||
},
|
||||
})
|
||||
{ throwOnError: true },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,10 +753,10 @@ export namespace ACP {
|
||||
if (configured) return configured
|
||||
|
||||
const model = await sdk.config
|
||||
.get({ throwOnError: true, query: { directory: cwd } })
|
||||
.get({ directory: cwd }, { throwOnError: true })
|
||||
.then((resp) => {
|
||||
const cfg = resp.data
|
||||
if (!cfg.model) return undefined
|
||||
if (!cfg || !cfg.model) return undefined
|
||||
const parsed = Provider.parseModel(cfg.model)
|
||||
return {
|
||||
providerID: parsed.providerID,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { RequestError, type McpServer } from "@agentclientprotocol/sdk"
|
||||
import type { ACPSessionState } from "./types"
|
||||
import { Log } from "@/util/log"
|
||||
import type { OpencodeClient } from "@opencode-ai/sdk"
|
||||
import type { OpencodeClient } from "@opencode-ai/sdk/v2"
|
||||
|
||||
const log = Log.create({ service: "acp-session-manager" })
|
||||
|
||||
@@ -15,16 +15,14 @@ export class ACPSessionManager {
|
||||
|
||||
async create(cwd: string, mcpServers: McpServer[], model?: ACPSessionState["model"]): Promise<ACPSessionState> {
|
||||
const session = await this.sdk.session
|
||||
.create({
|
||||
body: {
|
||||
.create(
|
||||
{
|
||||
title: `ACP Session ${crypto.randomUUID()}`,
|
||||
},
|
||||
query: {
|
||||
directory: cwd,
|
||||
},
|
||||
throwOnError: true,
|
||||
})
|
||||
.then((x) => x.data)
|
||||
{ throwOnError: true },
|
||||
)
|
||||
.then((x) => x.data!)
|
||||
|
||||
const sessionId = session.id
|
||||
const resolvedModel = model
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { McpServer } from "@agentclientprotocol/sdk"
|
||||
import type { OpencodeClient } from "@opencode-ai/sdk"
|
||||
import type { OpencodeClient } from "@opencode-ai/sdk/v2"
|
||||
|
||||
export interface ACPSessionState {
|
||||
id: string
|
||||
|
||||
@@ -35,16 +35,22 @@ export namespace Auth {
|
||||
const filepath = path.join(Global.Path.data, "auth.json")
|
||||
|
||||
export async function get(providerID: string) {
|
||||
const file = Bun.file(filepath)
|
||||
return file
|
||||
.json()
|
||||
.catch(() => ({}))
|
||||
.then((x) => x[providerID] as Info | undefined)
|
||||
const auth = await all()
|
||||
return auth[providerID]
|
||||
}
|
||||
|
||||
export async function all(): Promise<Record<string, Info>> {
|
||||
const file = Bun.file(filepath)
|
||||
return file.json().catch(() => ({}))
|
||||
const data = await file.json().catch(() => ({}) as Record<string, unknown>)
|
||||
return Object.entries(data).reduce(
|
||||
(acc, [key, value]) => {
|
||||
const parsed = Info.safeParse(value)
|
||||
if (!parsed.success) return acc
|
||||
acc[key] = parsed.data
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, Info>,
|
||||
)
|
||||
}
|
||||
|
||||
export async function set(key: string, info: Info) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { cmd } from "./cmd"
|
||||
import { AgentSideConnection, ndJsonStream } from "@agentclientprotocol/sdk"
|
||||
import { ACP } from "@/acp/agent"
|
||||
import { Server } from "@/server/server"
|
||||
import { createOpencodeClient } from "@opencode-ai/sdk"
|
||||
import { createOpencodeClient } from "@opencode-ai/sdk/v2"
|
||||
|
||||
const log = Log.create({ service: "acp-command" })
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export const AuthListCommand = cmd({
|
||||
const homedir = os.homedir()
|
||||
const displayPath = authPath.startsWith(homedir) ? authPath.replace(homedir, "~") : authPath
|
||||
prompts.intro(`Credentials ${UI.Style.TEXT_DIM}${displayPath}`)
|
||||
const results = await Auth.all().then((x) => Object.entries(x))
|
||||
const results = Object.entries(await Auth.all())
|
||||
const database = await ModelsDev.get()
|
||||
|
||||
for (const [providerID, result] of results) {
|
||||
@@ -143,7 +143,10 @@ export const AuthLoginCommand = cmd({
|
||||
map((x) => ({
|
||||
label: x.name,
|
||||
value: x.id,
|
||||
hint: priority[x.id] <= 1 ? "recommended" : undefined,
|
||||
hint: {
|
||||
opencode: "recommended",
|
||||
anthropic: "Claude Max or API key",
|
||||
}[x.id],
|
||||
})),
|
||||
),
|
||||
{
|
||||
|
||||
@@ -5,6 +5,26 @@ export const GenerateCommand = {
|
||||
command: "generate",
|
||||
handler: async () => {
|
||||
const specs = await Server.openapi()
|
||||
for (const item of Object.values(specs.paths)) {
|
||||
for (const method of ["get", "post", "put", "delete", "patch"] as const) {
|
||||
const operation = item[method]
|
||||
if (!operation?.operationId) continue
|
||||
// @ts-expect-error
|
||||
operation["x-codeSamples"] = [
|
||||
{
|
||||
lang: "js",
|
||||
source: [
|
||||
`import { createOpencodeClient } from "@opencode-ai/sdk`,
|
||||
``,
|
||||
`const client = createOpencodeClient()`,
|
||||
`await client.${operation.operationId}({`,
|
||||
` ...`,
|
||||
`})`,
|
||||
].join("\n"),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
const json = JSON.stringify(specs, null, 2)
|
||||
|
||||
// Wait for stdout to finish writing before process.exit() is called
|
||||
|
||||
@@ -3,13 +3,272 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js"
|
||||
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
|
||||
import * as prompts from "@clack/prompts"
|
||||
import { UI } from "../ui"
|
||||
import { MCP } from "../../mcp"
|
||||
import { McpAuth } from "../../mcp/auth"
|
||||
import { Config } from "../../config/config"
|
||||
import { Instance } from "../../project/instance"
|
||||
import path from "path"
|
||||
import os from "os"
|
||||
import { Global } from "../../global"
|
||||
|
||||
export const McpCommand = cmd({
|
||||
command: "mcp",
|
||||
builder: (yargs) => yargs.command(McpAddCommand).demandCommand(),
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.command(McpAddCommand)
|
||||
.command(McpListCommand)
|
||||
.command(McpAuthCommand)
|
||||
.command(McpLogoutCommand)
|
||||
.demandCommand(),
|
||||
async handler() {},
|
||||
})
|
||||
|
||||
export const McpListCommand = cmd({
|
||||
command: "list",
|
||||
aliases: ["ls"],
|
||||
describe: "list MCP servers and their status",
|
||||
async handler() {
|
||||
await Instance.provide({
|
||||
directory: process.cwd(),
|
||||
async fn() {
|
||||
UI.empty()
|
||||
prompts.intro("MCP Servers")
|
||||
|
||||
const config = await Config.get()
|
||||
const mcpServers = config.mcp ?? {}
|
||||
const statuses = await MCP.status()
|
||||
|
||||
if (Object.keys(mcpServers).length === 0) {
|
||||
prompts.log.warn("No MCP servers configured")
|
||||
prompts.outro("Add servers with: opencode mcp add")
|
||||
return
|
||||
}
|
||||
|
||||
for (const [name, serverConfig] of Object.entries(mcpServers)) {
|
||||
const status = statuses[name]
|
||||
const hasOAuth = serverConfig.type === "remote" && !!serverConfig.oauth
|
||||
const hasStoredTokens = await MCP.hasStoredTokens(name)
|
||||
|
||||
let statusIcon: string
|
||||
let statusText: string
|
||||
let hint = ""
|
||||
|
||||
if (!status) {
|
||||
statusIcon = "○"
|
||||
statusText = "not initialized"
|
||||
} else if (status.status === "connected") {
|
||||
statusIcon = "✓"
|
||||
statusText = "connected"
|
||||
if (hasOAuth && hasStoredTokens) {
|
||||
hint = " (OAuth)"
|
||||
}
|
||||
} else if (status.status === "disabled") {
|
||||
statusIcon = "○"
|
||||
statusText = "disabled"
|
||||
} else if (status.status === "needs_auth") {
|
||||
statusIcon = "⚠"
|
||||
statusText = "needs authentication"
|
||||
} else if (status.status === "needs_client_registration") {
|
||||
statusIcon = "✗"
|
||||
statusText = "needs client registration"
|
||||
hint = "\n " + status.error
|
||||
} else {
|
||||
statusIcon = "✗"
|
||||
statusText = "failed"
|
||||
hint = "\n " + status.error
|
||||
}
|
||||
|
||||
const typeHint = serverConfig.type === "remote" ? serverConfig.url : serverConfig.command.join(" ")
|
||||
prompts.log.info(
|
||||
`${statusIcon} ${name} ${UI.Style.TEXT_DIM}${statusText}${hint}\n ${UI.Style.TEXT_DIM}${typeHint}`,
|
||||
)
|
||||
}
|
||||
|
||||
prompts.outro(`${Object.keys(mcpServers).length} server(s)`)
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const McpAuthCommand = cmd({
|
||||
command: "auth [name]",
|
||||
describe: "authenticate with an OAuth-enabled MCP server",
|
||||
builder: (yargs) =>
|
||||
yargs.positional("name", {
|
||||
describe: "name of the MCP server",
|
||||
type: "string",
|
||||
}),
|
||||
async handler(args) {
|
||||
await Instance.provide({
|
||||
directory: process.cwd(),
|
||||
async fn() {
|
||||
UI.empty()
|
||||
prompts.intro("MCP OAuth Authentication")
|
||||
|
||||
const config = await Config.get()
|
||||
const mcpServers = config.mcp ?? {}
|
||||
|
||||
// Get OAuth-enabled servers
|
||||
const oauthServers = Object.entries(mcpServers).filter(([_, cfg]) => cfg.type === "remote" && !!cfg.oauth)
|
||||
|
||||
if (oauthServers.length === 0) {
|
||||
prompts.log.warn("No OAuth-enabled MCP servers configured")
|
||||
prompts.log.info("Add OAuth config to a remote MCP server in opencode.json:")
|
||||
prompts.log.info(`
|
||||
"mcp": {
|
||||
"my-server": {
|
||||
"type": "remote",
|
||||
"url": "https://example.com/mcp",
|
||||
"oauth": {
|
||||
"scope": "tools:read"
|
||||
}
|
||||
}
|
||||
}`)
|
||||
prompts.outro("Done")
|
||||
return
|
||||
}
|
||||
|
||||
let serverName = args.name
|
||||
if (!serverName) {
|
||||
const selected = await prompts.select({
|
||||
message: "Select MCP server to authenticate",
|
||||
options: oauthServers.map(([name, cfg]) => ({
|
||||
label: name,
|
||||
value: name,
|
||||
hint: cfg.type === "remote" ? cfg.url : undefined,
|
||||
})),
|
||||
})
|
||||
if (prompts.isCancel(selected)) throw new UI.CancelledError()
|
||||
serverName = selected
|
||||
}
|
||||
|
||||
const serverConfig = mcpServers[serverName]
|
||||
if (!serverConfig) {
|
||||
prompts.log.error(`MCP server not found: ${serverName}`)
|
||||
prompts.outro("Done")
|
||||
return
|
||||
}
|
||||
|
||||
if (serverConfig.type !== "remote" || !serverConfig.oauth) {
|
||||
prompts.log.error(`MCP server ${serverName} does not have OAuth configured`)
|
||||
prompts.outro("Done")
|
||||
return
|
||||
}
|
||||
|
||||
// Check if already authenticated
|
||||
const hasTokens = await MCP.hasStoredTokens(serverName)
|
||||
if (hasTokens) {
|
||||
const confirm = await prompts.confirm({
|
||||
message: `${serverName} already has stored credentials. Re-authenticate?`,
|
||||
})
|
||||
if (prompts.isCancel(confirm) || !confirm) {
|
||||
prompts.outro("Cancelled")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const spinner = prompts.spinner()
|
||||
spinner.start("Starting OAuth flow...")
|
||||
|
||||
try {
|
||||
const status = await MCP.authenticate(serverName)
|
||||
|
||||
if (status.status === "connected") {
|
||||
spinner.stop("Authentication successful!")
|
||||
} else if (status.status === "needs_client_registration") {
|
||||
spinner.stop("Authentication failed", 1)
|
||||
prompts.log.error(status.error)
|
||||
prompts.log.info("Add clientId to your MCP server config:")
|
||||
prompts.log.info(`
|
||||
"mcp": {
|
||||
"${serverName}": {
|
||||
"type": "remote",
|
||||
"url": "${serverConfig.url}",
|
||||
"oauth": {
|
||||
"clientId": "your-client-id",
|
||||
"clientSecret": "your-client-secret"
|
||||
}
|
||||
}
|
||||
}`)
|
||||
} else if (status.status === "failed") {
|
||||
spinner.stop("Authentication failed", 1)
|
||||
prompts.log.error(status.error)
|
||||
} else {
|
||||
spinner.stop("Unexpected status: " + status.status, 1)
|
||||
}
|
||||
} catch (error) {
|
||||
spinner.stop("Authentication failed", 1)
|
||||
prompts.log.error(error instanceof Error ? error.message : String(error))
|
||||
}
|
||||
|
||||
prompts.outro("Done")
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const McpLogoutCommand = cmd({
|
||||
command: "logout [name]",
|
||||
describe: "remove OAuth credentials for an MCP server",
|
||||
builder: (yargs) =>
|
||||
yargs.positional("name", {
|
||||
describe: "name of the MCP server",
|
||||
type: "string",
|
||||
}),
|
||||
async handler(args) {
|
||||
await Instance.provide({
|
||||
directory: process.cwd(),
|
||||
async fn() {
|
||||
UI.empty()
|
||||
prompts.intro("MCP OAuth Logout")
|
||||
|
||||
const authPath = path.join(Global.Path.data, "mcp-auth.json")
|
||||
const credentials = await McpAuth.all()
|
||||
const serverNames = Object.keys(credentials)
|
||||
|
||||
if (serverNames.length === 0) {
|
||||
prompts.log.warn("No MCP OAuth credentials stored")
|
||||
prompts.outro("Done")
|
||||
return
|
||||
}
|
||||
|
||||
let serverName = args.name
|
||||
if (!serverName) {
|
||||
const selected = await prompts.select({
|
||||
message: "Select MCP server to logout",
|
||||
options: serverNames.map((name) => {
|
||||
const entry = credentials[name]
|
||||
const hasTokens = !!entry.tokens
|
||||
const hasClient = !!entry.clientInfo
|
||||
let hint = ""
|
||||
if (hasTokens && hasClient) hint = "tokens + client"
|
||||
else if (hasTokens) hint = "tokens"
|
||||
else if (hasClient) hint = "client registration"
|
||||
return {
|
||||
label: name,
|
||||
value: name,
|
||||
hint,
|
||||
}
|
||||
}),
|
||||
})
|
||||
if (prompts.isCancel(selected)) throw new UI.CancelledError()
|
||||
serverName = selected
|
||||
}
|
||||
|
||||
if (!credentials[serverName]) {
|
||||
prompts.log.error(`No credentials found for: ${serverName}`)
|
||||
prompts.outro("Done")
|
||||
return
|
||||
}
|
||||
|
||||
await MCP.removeAuth(serverName)
|
||||
prompts.log.success(`Removed OAuth credentials for ${serverName}`)
|
||||
prompts.outro("Done")
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const McpAddCommand = cmd({
|
||||
command: "add",
|
||||
describe: "add an MCP server",
|
||||
@@ -66,13 +325,74 @@ export const McpAddCommand = cmd({
|
||||
})
|
||||
if (prompts.isCancel(url)) throw new UI.CancelledError()
|
||||
|
||||
const client = new Client({
|
||||
name: "opencode",
|
||||
version: "1.0.0",
|
||||
const useOAuth = await prompts.confirm({
|
||||
message: "Does this server require OAuth authentication?",
|
||||
initialValue: false,
|
||||
})
|
||||
const transport = new StreamableHTTPClientTransport(new URL(url))
|
||||
await client.connect(transport)
|
||||
prompts.log.info(`Remote MCP server "${name}" configured with URL: ${url}`)
|
||||
if (prompts.isCancel(useOAuth)) throw new UI.CancelledError()
|
||||
|
||||
if (useOAuth) {
|
||||
const hasClientId = await prompts.confirm({
|
||||
message: "Do you have a pre-registered client ID?",
|
||||
initialValue: false,
|
||||
})
|
||||
if (prompts.isCancel(hasClientId)) throw new UI.CancelledError()
|
||||
|
||||
if (hasClientId) {
|
||||
const clientId = await prompts.text({
|
||||
message: "Enter client ID",
|
||||
validate: (x) => (x && x.length > 0 ? undefined : "Required"),
|
||||
})
|
||||
if (prompts.isCancel(clientId)) throw new UI.CancelledError()
|
||||
|
||||
const hasSecret = await prompts.confirm({
|
||||
message: "Do you have a client secret?",
|
||||
initialValue: false,
|
||||
})
|
||||
if (prompts.isCancel(hasSecret)) throw new UI.CancelledError()
|
||||
|
||||
let clientSecret: string | undefined
|
||||
if (hasSecret) {
|
||||
const secret = await prompts.password({
|
||||
message: "Enter client secret",
|
||||
})
|
||||
if (prompts.isCancel(secret)) throw new UI.CancelledError()
|
||||
clientSecret = secret
|
||||
}
|
||||
|
||||
prompts.log.info(`Remote MCP server "${name}" configured with OAuth (client ID: ${clientId})`)
|
||||
prompts.log.info("Add this to your opencode.json:")
|
||||
prompts.log.info(`
|
||||
"mcp": {
|
||||
"${name}": {
|
||||
"type": "remote",
|
||||
"url": "${url}",
|
||||
"oauth": {
|
||||
"clientId": "${clientId}"${clientSecret ? `,\n "clientSecret": "${clientSecret}"` : ""}
|
||||
}
|
||||
}
|
||||
}`)
|
||||
} else {
|
||||
prompts.log.info(`Remote MCP server "${name}" configured with OAuth (dynamic registration)`)
|
||||
prompts.log.info("Add this to your opencode.json:")
|
||||
prompts.log.info(`
|
||||
"mcp": {
|
||||
"${name}": {
|
||||
"type": "remote",
|
||||
"url": "${url}",
|
||||
"oauth": {}
|
||||
}
|
||||
}`)
|
||||
}
|
||||
} else {
|
||||
const client = new Client({
|
||||
name: "opencode",
|
||||
version: "1.0.0",
|
||||
})
|
||||
const transport = new StreamableHTTPClientTransport(new URL(url))
|
||||
await client.connect(transport)
|
||||
prompts.log.info(`Remote MCP server "${name}" configured with URL: ${url}`)
|
||||
}
|
||||
}
|
||||
|
||||
prompts.outro("MCP server added successfully")
|
||||
|
||||
@@ -7,7 +7,7 @@ import { bootstrap } from "../bootstrap"
|
||||
import { Command } from "../../command"
|
||||
import { EOL } from "os"
|
||||
import { select } from "@clack/prompts"
|
||||
import { createOpencodeClient, type OpencodeClient } from "@opencode-ai/sdk"
|
||||
import { createOpencodeClient, type OpencodeClient } from "@opencode-ai/sdk/v2"
|
||||
import { Server } from "../../server/server"
|
||||
import { Provider } from "../../provider/provider"
|
||||
|
||||
@@ -212,9 +212,10 @@ export const RunCommand = cmd({
|
||||
initialValue: "once",
|
||||
}).catch(() => "reject")
|
||||
const response = (result.toString().includes("cancel") ? "reject" : result) as "once" | "always" | "reject"
|
||||
await sdk.postSessionIdPermissionsPermissionId({
|
||||
path: { id: sessionID, permissionID: permission.id },
|
||||
body: { response },
|
||||
await sdk.permission.respond({
|
||||
sessionID,
|
||||
permissionID: permission.id,
|
||||
response,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -222,23 +223,19 @@ export const RunCommand = cmd({
|
||||
|
||||
if (args.command) {
|
||||
await sdk.session.command({
|
||||
path: { id: sessionID },
|
||||
body: {
|
||||
agent: args.agent || "build",
|
||||
model: args.model,
|
||||
command: args.command,
|
||||
arguments: message,
|
||||
},
|
||||
sessionID,
|
||||
agent: args.agent || "build",
|
||||
model: args.model,
|
||||
command: args.command,
|
||||
arguments: message,
|
||||
})
|
||||
} else {
|
||||
const modelParam = args.model ? Provider.parseModel(args.model) : undefined
|
||||
await sdk.session.prompt({
|
||||
path: { id: sessionID },
|
||||
body: {
|
||||
agent: args.agent || "build",
|
||||
model: modelParam,
|
||||
parts: [...fileParts, { type: "text", text: message }],
|
||||
},
|
||||
sessionID,
|
||||
agent: args.agent || "build",
|
||||
model: modelParam,
|
||||
parts: [...fileParts, { type: "text", text: message }],
|
||||
})
|
||||
}
|
||||
|
||||
@@ -263,7 +260,7 @@ export const RunCommand = cmd({
|
||||
: args.title
|
||||
: undefined
|
||||
|
||||
const result = await sdk.session.create({ body: title ? { title } : {} })
|
||||
const result = await sdk.session.create(title ? { title } : {})
|
||||
return result.data?.id
|
||||
})()
|
||||
|
||||
@@ -274,7 +271,7 @@ export const RunCommand = cmd({
|
||||
|
||||
const cfgResult = await sdk.config.get()
|
||||
if (cfgResult.data && (cfgResult.data.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share)) {
|
||||
const shareResult = await sdk.session.share({ path: { id: sessionID } }).catch((error) => {
|
||||
const shareResult = await sdk.session.share({ sessionID }).catch((error) => {
|
||||
if (error instanceof Error && error.message.includes("disabled")) {
|
||||
UI.println(UI.Style.TEXT_DANGER_BOLD + "! " + error.message)
|
||||
}
|
||||
@@ -315,7 +312,7 @@ export const RunCommand = cmd({
|
||||
: args.title
|
||||
: undefined
|
||||
|
||||
const result = await sdk.session.create({ body: title ? { title } : {} })
|
||||
const result = await sdk.session.create(title ? { title } : {})
|
||||
return result.data?.id
|
||||
})()
|
||||
|
||||
@@ -327,7 +324,7 @@ export const RunCommand = cmd({
|
||||
|
||||
const cfgResult = await sdk.config.get()
|
||||
if (cfgResult.data && (cfgResult.data.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share)) {
|
||||
const shareResult = await sdk.session.share({ path: { id: sessionID } }).catch((error) => {
|
||||
const shareResult = await sdk.session.share({ sessionID }).catch((error) => {
|
||||
if (error instanceof Error && error.message.includes("disabled")) {
|
||||
UI.println(UI.Style.TEXT_DANGER_BOLD + "! " + error.message)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { SDKProvider, useSDK } from "@tui/context/sdk"
|
||||
import { SyncProvider, useSync } from "@tui/context/sync"
|
||||
import { LocalProvider, useLocal } from "@tui/context/local"
|
||||
import { DialogModel, useConnected } from "@tui/component/dialog-model"
|
||||
import { DialogMcp } from "@tui/component/dialog-mcp"
|
||||
import { DialogStatus } from "@tui/component/dialog-status"
|
||||
import { DialogThemeList } from "@tui/component/dialog-theme-list"
|
||||
import { DialogHelp } from "./ui/dialog-help"
|
||||
@@ -301,6 +302,14 @@ function App() {
|
||||
dialog.replace(() => <DialogAgent />)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Toggle MCPs",
|
||||
value: "mcp.list",
|
||||
category: "Agent",
|
||||
onSelect: () => {
|
||||
dialog.replace(() => <DialogMcp />)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Agent cycle",
|
||||
value: "agent.cycle",
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from "solid-js"
|
||||
import { useKeyboard } from "@opentui/solid"
|
||||
import { useKeybind } from "@tui/context/keybind"
|
||||
import type { KeybindsConfig } from "@opencode-ai/sdk"
|
||||
import type { KeybindsConfig } from "@opencode-ai/sdk/v2"
|
||||
|
||||
type Context = ReturnType<typeof init>
|
||||
const ctx = createContext<Context>()
|
||||
|
||||
86
packages/opencode/src/cli/cmd/tui/component/dialog-mcp.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import { createMemo, createSignal } from "solid-js"
|
||||
import { useLocal } from "@tui/context/local"
|
||||
import { useSync } from "@tui/context/sync"
|
||||
import { map, pipe, entries, sortBy } from "remeda"
|
||||
import { DialogSelect, type DialogSelectRef, type DialogSelectOption } from "@tui/ui/dialog-select"
|
||||
import { useTheme } from "../context/theme"
|
||||
import { Keybind } from "@/util/keybind"
|
||||
import { TextAttributes } from "@opentui/core"
|
||||
import { useSDK } from "@tui/context/sdk"
|
||||
|
||||
function Status(props: { enabled: boolean; loading: boolean }) {
|
||||
const { theme } = useTheme()
|
||||
if (props.loading) {
|
||||
return <span style={{ fg: theme.textMuted }}>⋯ Loading</span>
|
||||
}
|
||||
if (props.enabled) {
|
||||
return <span style={{ fg: theme.success, attributes: TextAttributes.BOLD }}>✓ Enabled</span>
|
||||
}
|
||||
return <span style={{ fg: theme.textMuted }}>○ Disabled</span>
|
||||
}
|
||||
|
||||
export function DialogMcp() {
|
||||
const local = useLocal()
|
||||
const sync = useSync()
|
||||
const sdk = useSDK()
|
||||
const [, setRef] = createSignal<DialogSelectRef<unknown>>()
|
||||
const [loading, setLoading] = createSignal<string | null>(null)
|
||||
|
||||
const options = createMemo(() => {
|
||||
// Track sync data and loading state to trigger re-render when they change
|
||||
const mcpData = sync.data.mcp
|
||||
const loadingMcp = loading()
|
||||
|
||||
return pipe(
|
||||
mcpData ?? {},
|
||||
entries(),
|
||||
sortBy(([name]) => name),
|
||||
map(([name, status]) => ({
|
||||
value: name,
|
||||
title: name,
|
||||
description: status.status === "failed" ? "failed" : status.status,
|
||||
footer: <Status enabled={local.mcp.isEnabled(name)} loading={loadingMcp === name} />,
|
||||
category: undefined,
|
||||
})),
|
||||
)
|
||||
})
|
||||
|
||||
const keybinds = createMemo(() => [
|
||||
{
|
||||
keybind: Keybind.parse("space")[0],
|
||||
title: "toggle",
|
||||
onTrigger: async (option: DialogSelectOption<string>) => {
|
||||
// Prevent toggling while an operation is already in progress
|
||||
if (loading() !== null) return
|
||||
|
||||
setLoading(option.value)
|
||||
try {
|
||||
await local.mcp.toggle(option.value)
|
||||
// Refresh MCP status from server
|
||||
const status = await sdk.client.mcp.status()
|
||||
if (status.data) {
|
||||
sync.set("mcp", status.data)
|
||||
} else {
|
||||
console.error("Failed to refresh MCP status: no data returned")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to toggle MCP:", error)
|
||||
} finally {
|
||||
setLoading(null)
|
||||
}
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
return (
|
||||
<DialogSelect
|
||||
ref={setRef}
|
||||
title="MCPs"
|
||||
options={options()}
|
||||
keybind={keybinds()}
|
||||
onSelect={(option) => {
|
||||
// Don't close on select, only on escape
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { useSDK } from "../context/sdk"
|
||||
import { DialogPrompt } from "../ui/dialog-prompt"
|
||||
import { useTheme } from "../context/theme"
|
||||
import { TextAttributes } from "@opentui/core"
|
||||
import type { ProviderAuthAuthorization } from "@opencode-ai/sdk"
|
||||
import type { ProviderAuthAuthorization } from "@opencode-ai/sdk/v2"
|
||||
import { DialogModel } from "./dialog-model"
|
||||
|
||||
const PROVIDER_PRIORITY: Record<string, number> = {
|
||||
@@ -64,12 +64,8 @@ export function createDialogProviderOptions() {
|
||||
const method = methods[index]
|
||||
if (method.type === "oauth") {
|
||||
const result = await sdk.client.provider.oauth.authorize({
|
||||
path: {
|
||||
id: provider.id,
|
||||
},
|
||||
body: {
|
||||
method: index,
|
||||
},
|
||||
providerID: provider.id,
|
||||
method: index,
|
||||
})
|
||||
if (result.data?.method === "code") {
|
||||
dialog.replace(() => (
|
||||
@@ -111,12 +107,8 @@ function AutoMethod(props: AutoMethodProps) {
|
||||
|
||||
onMount(async () => {
|
||||
const result = await sdk.client.provider.oauth.callback({
|
||||
path: {
|
||||
id: props.providerID,
|
||||
},
|
||||
body: {
|
||||
method: props.index,
|
||||
},
|
||||
providerID: props.providerID,
|
||||
method: props.index,
|
||||
})
|
||||
if (result.error) {
|
||||
dialog.clear()
|
||||
@@ -161,13 +153,9 @@ function CodeMethod(props: CodeMethodProps) {
|
||||
placeholder="Authorization code"
|
||||
onConfirm={async (value) => {
|
||||
const { error } = await sdk.client.provider.oauth.callback({
|
||||
path: {
|
||||
id: props.providerID,
|
||||
},
|
||||
body: {
|
||||
method: props.index,
|
||||
code: value,
|
||||
},
|
||||
providerID: props.providerID,
|
||||
method: props.index,
|
||||
code: value,
|
||||
})
|
||||
if (!error) {
|
||||
await sdk.client.instance.dispose()
|
||||
@@ -219,10 +207,8 @@ function ApiMethod(props: ApiMethodProps) {
|
||||
onConfirm={async (value) => {
|
||||
if (!value) return
|
||||
sdk.client.auth.set({
|
||||
path: {
|
||||
id: props.providerID,
|
||||
},
|
||||
body: {
|
||||
providerID: props.providerID,
|
||||
auth: {
|
||||
type: "api",
|
||||
key: value,
|
||||
},
|
||||
|
||||
@@ -26,6 +26,7 @@ export function DialogSessionList() {
|
||||
const today = new Date().toDateString()
|
||||
return sync.data.session
|
||||
.filter((x) => x.parentID === undefined)
|
||||
.toSorted((a, b) => b.time.updated - a.time.updated)
|
||||
.map((x) => {
|
||||
const date = new Date(x.time.updated)
|
||||
let category = date.toDateString()
|
||||
@@ -74,9 +75,7 @@ export function DialogSessionList() {
|
||||
onTrigger: async (option) => {
|
||||
if (toDelete() === option.value) {
|
||||
sdk.client.session.delete({
|
||||
path: {
|
||||
id: option.value,
|
||||
},
|
||||
sessionID: option.value,
|
||||
})
|
||||
setToDelete(undefined)
|
||||
// dialog.clear()
|
||||
|
||||
@@ -20,12 +20,8 @@ export function DialogSessionRename(props: DialogSessionRenameProps) {
|
||||
value={session()?.title}
|
||||
onConfirm={(value) => {
|
||||
sdk.client.session.update({
|
||||
path: {
|
||||
id: props.session,
|
||||
},
|
||||
body: {
|
||||
title: value,
|
||||
},
|
||||
sessionID: props.session,
|
||||
title: value,
|
||||
})
|
||||
dialog.clear()
|
||||
}}
|
||||
|
||||
@@ -28,11 +28,15 @@ export function DialogStatus() {
|
||||
<text
|
||||
flexShrink={0}
|
||||
style={{
|
||||
fg: {
|
||||
connected: theme.success,
|
||||
failed: theme.error,
|
||||
disabled: theme.textMuted,
|
||||
}[item.status],
|
||||
fg: (
|
||||
{
|
||||
connected: theme.success,
|
||||
failed: theme.error,
|
||||
disabled: theme.textMuted,
|
||||
needs_auth: theme.warning,
|
||||
needs_client_registration: theme.error,
|
||||
} as Record<string, typeof theme.success>
|
||||
)[item.status],
|
||||
}}
|
||||
>
|
||||
•
|
||||
@@ -40,10 +44,16 @@ export function DialogStatus() {
|
||||
<text fg={theme.text} wrapMode="word">
|
||||
<b>{key}</b>{" "}
|
||||
<span style={{ fg: theme.textMuted }}>
|
||||
<Switch>
|
||||
<Switch fallback={item.status}>
|
||||
<Match when={item.status === "connected"}>Connected</Match>
|
||||
<Match when={item.status === "failed" && item}>{(val) => val().error}</Match>
|
||||
<Match when={item.status === "disabled"}>Disabled in configuration</Match>
|
||||
<Match when={(item.status as string) === "needs_auth"}>
|
||||
Needs authentication (run: opencode mcp auth {key})
|
||||
</Match>
|
||||
<Match when={(item.status as string) === "needs_client_registration" && item}>
|
||||
{(val) => (val() as { error: string }).error}
|
||||
</Match>
|
||||
</Switch>
|
||||
</span>
|
||||
</text>
|
||||
|
||||
@@ -16,9 +16,7 @@ export function DialogTag(props: { onSelect?: (value: string) => void }) {
|
||||
() => [store.filter],
|
||||
async () => {
|
||||
const result = await sdk.client.find.files({
|
||||
query: {
|
||||
query: store.filter,
|
||||
},
|
||||
query: store.filter,
|
||||
})
|
||||
if (result.error) return []
|
||||
const sliced = (result.data ?? []).slice(0, 5)
|
||||
|
||||
@@ -5,10 +5,12 @@ import { onCleanup, onMount } from "solid-js"
|
||||
|
||||
export function DialogThemeList() {
|
||||
const theme = useTheme()
|
||||
const options = Object.keys(theme.all()).map((value) => ({
|
||||
title: value,
|
||||
value: value,
|
||||
}))
|
||||
const options = Object.keys(theme.all())
|
||||
.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" }))
|
||||
.map((value) => ({
|
||||
title: value,
|
||||
value: value,
|
||||
}))
|
||||
const dialog = useDialog()
|
||||
let confirmed = false
|
||||
let ref: DialogSelectRef<string>
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import type { BoxRenderable, TextareaRenderable, KeyEvent } from "@opentui/core"
|
||||
import fuzzysort from "fuzzysort"
|
||||
import { firstBy } from "remeda"
|
||||
import { createMemo, createResource, createEffect, onMount, For, Show } from "solid-js"
|
||||
import { createMemo, createResource, createEffect, onMount, onCleanup, For, Show, createSignal } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { useSDK } from "@tui/context/sdk"
|
||||
import { useSync } from "@tui/context/sync"
|
||||
import { useTheme, selectedForeground } from "@tui/context/theme"
|
||||
import { SplitBorder } from "@tui/component/border"
|
||||
import { useCommandDialog } from "@tui/component/dialog-command"
|
||||
import { useTerminalDimensions } from "@opentui/solid"
|
||||
import { Locale } from "@/util/locale"
|
||||
import type { PromptInfo } from "./history"
|
||||
|
||||
@@ -41,13 +42,43 @@ export function Autocomplete(props: {
|
||||
const sync = useSync()
|
||||
const command = useCommandDialog()
|
||||
const { theme } = useTheme()
|
||||
const dimensions = useTerminalDimensions()
|
||||
|
||||
const [store, setStore] = createStore({
|
||||
index: 0,
|
||||
selected: 0,
|
||||
visible: false as AutocompleteRef["visible"],
|
||||
position: { x: 0, y: 0, width: 0 },
|
||||
})
|
||||
|
||||
const [positionTick, setPositionTick] = createSignal(0)
|
||||
|
||||
createEffect(() => {
|
||||
if (store.visible) {
|
||||
let lastPos = { x: 0, y: 0, width: 0 }
|
||||
const interval = setInterval(() => {
|
||||
const anchor = props.anchor()
|
||||
if (anchor.x !== lastPos.x || anchor.y !== lastPos.y || anchor.width !== lastPos.width) {
|
||||
lastPos = { x: anchor.x, y: anchor.y, width: anchor.width }
|
||||
setPositionTick((t) => t + 1)
|
||||
}
|
||||
}, 50)
|
||||
|
||||
onCleanup(() => clearInterval(interval))
|
||||
}
|
||||
})
|
||||
|
||||
const position = createMemo(() => {
|
||||
if (!store.visible) return { x: 0, y: 0, width: 0 }
|
||||
const dims = dimensions()
|
||||
positionTick()
|
||||
const anchor = props.anchor()
|
||||
return {
|
||||
x: anchor.x,
|
||||
y: anchor.y,
|
||||
width: anchor.width,
|
||||
}
|
||||
})
|
||||
|
||||
const filter = createMemo(() => {
|
||||
if (!store.visible) return
|
||||
// Track props.value to make memo reactive to text changes
|
||||
@@ -109,16 +140,14 @@ export function Autocomplete(props: {
|
||||
|
||||
// Get files from SDK
|
||||
const result = await sdk.client.find.files({
|
||||
query: {
|
||||
query: query ?? "",
|
||||
},
|
||||
query: query ?? "",
|
||||
})
|
||||
|
||||
const options: AutocompleteOption[] = []
|
||||
|
||||
// Add file options
|
||||
if (!result.error && result.data) {
|
||||
const width = store.position.width - 4
|
||||
const width = props.anchor().width - 4
|
||||
options.push(
|
||||
...result.data.map(
|
||||
(item): AutocompleteOption => ({
|
||||
@@ -278,10 +307,14 @@ export function Autocomplete(props: {
|
||||
},
|
||||
{
|
||||
display: "/status",
|
||||
aliases: ["/mcp"],
|
||||
description: "show status",
|
||||
onSelect: () => command.trigger("opencode.status"),
|
||||
},
|
||||
{
|
||||
display: "/mcp",
|
||||
description: "toggle MCPs",
|
||||
onSelect: () => command.trigger("mcp.list"),
|
||||
},
|
||||
{
|
||||
display: "/theme",
|
||||
description: "toggle theme",
|
||||
@@ -361,11 +394,6 @@ export function Autocomplete(props: {
|
||||
setStore({
|
||||
visible: mode,
|
||||
index: props.input().cursorOffset,
|
||||
position: {
|
||||
x: props.anchor().x,
|
||||
y: props.anchor().y,
|
||||
width: props.anchor().width,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -457,9 +485,9 @@ export function Autocomplete(props: {
|
||||
<box
|
||||
visible={store.visible !== false}
|
||||
position="absolute"
|
||||
top={store.position.y - height()}
|
||||
left={store.position.x}
|
||||
width={store.position.width}
|
||||
top={position().y - height()}
|
||||
left={position().x}
|
||||
width={position().width}
|
||||
zIndex={100}
|
||||
{...SplitBorder}
|
||||
borderColor={theme.border}
|
||||
@@ -469,7 +497,7 @@ export function Autocomplete(props: {
|
||||
each={options()}
|
||||
fallback={
|
||||
<box paddingLeft={1} paddingRight={1}>
|
||||
<text>No matching items</text>
|
||||
<text fg={theme.textMuted}>No matching items</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createStore, produce } from "solid-js/store"
|
||||
import { clone } from "remeda"
|
||||
import { createSimpleContext } from "../../context/helper"
|
||||
import { appendFile, writeFile } from "fs/promises"
|
||||
import type { AgentPart, FilePart, TextPart } from "@opencode-ai/sdk"
|
||||
import type { AgentPart, FilePart, TextPart } from "@opencode-ai/sdk/v2"
|
||||
|
||||
export type PromptInfo = {
|
||||
input: string
|
||||
|
||||
@@ -17,7 +17,7 @@ import { useRenderer } from "@opentui/solid"
|
||||
import { Editor } from "@tui/util/editor"
|
||||
import { useExit } from "../../context/exit"
|
||||
import { Clipboard } from "../../util/clipboard"
|
||||
import type { FilePart } from "@opencode-ai/sdk"
|
||||
import type { FilePart } from "@opencode-ai/sdk/v2"
|
||||
import { TuiEvent } from "../../event"
|
||||
import { iife } from "@/util/iife"
|
||||
import { Locale } from "@/util/locale"
|
||||
@@ -170,9 +170,7 @@ export function Prompt(props: PromptProps) {
|
||||
|
||||
if (store.interrupt >= 2) {
|
||||
sdk.client.session.abort({
|
||||
path: {
|
||||
id: props.sessionID,
|
||||
},
|
||||
sessionID: props.sessionID,
|
||||
})
|
||||
setStore("interrupt", 0)
|
||||
}
|
||||
@@ -447,17 +445,13 @@ export function Prompt(props: PromptProps) {
|
||||
|
||||
if (store.mode === "shell") {
|
||||
sdk.client.session.shell({
|
||||
path: {
|
||||
id: sessionID,
|
||||
},
|
||||
body: {
|
||||
agent: local.agent.current().name,
|
||||
model: {
|
||||
providerID: selectedModel.providerID,
|
||||
modelID: selectedModel.modelID,
|
||||
},
|
||||
command: inputText,
|
||||
sessionID,
|
||||
agent: local.agent.current().name,
|
||||
model: {
|
||||
providerID: selectedModel.providerID,
|
||||
modelID: selectedModel.modelID,
|
||||
},
|
||||
command: inputText,
|
||||
})
|
||||
setStore("mode", "normal")
|
||||
} else if (
|
||||
@@ -470,39 +464,31 @@ export function Prompt(props: PromptProps) {
|
||||
) {
|
||||
let [command, ...args] = inputText.split(" ")
|
||||
sdk.client.session.command({
|
||||
path: {
|
||||
id: sessionID,
|
||||
},
|
||||
body: {
|
||||
command: command.slice(1),
|
||||
arguments: args.join(" "),
|
||||
agent: local.agent.current().name,
|
||||
model: `${selectedModel.providerID}/${selectedModel.modelID}`,
|
||||
messageID,
|
||||
},
|
||||
sessionID,
|
||||
command: command.slice(1),
|
||||
arguments: args.join(" "),
|
||||
agent: local.agent.current().name,
|
||||
model: `${selectedModel.providerID}/${selectedModel.modelID}`,
|
||||
messageID,
|
||||
})
|
||||
} else {
|
||||
sdk.client.session.prompt({
|
||||
path: {
|
||||
id: sessionID,
|
||||
},
|
||||
body: {
|
||||
...selectedModel,
|
||||
messageID,
|
||||
agent: local.agent.current().name,
|
||||
model: selectedModel,
|
||||
parts: [
|
||||
{
|
||||
id: Identifier.ascending("part"),
|
||||
type: "text",
|
||||
text: inputText,
|
||||
},
|
||||
...nonTextParts.map((x) => ({
|
||||
id: Identifier.ascending("part"),
|
||||
...x,
|
||||
})),
|
||||
],
|
||||
},
|
||||
sessionID,
|
||||
...selectedModel,
|
||||
messageID,
|
||||
agent: local.agent.current().name,
|
||||
model: selectedModel,
|
||||
parts: [
|
||||
{
|
||||
id: Identifier.ascending("part"),
|
||||
type: "text",
|
||||
text: inputText,
|
||||
},
|
||||
...nonTextParts.map((x) => ({
|
||||
id: Identifier.ascending("part"),
|
||||
...x,
|
||||
})),
|
||||
],
|
||||
})
|
||||
}
|
||||
history.append(store.prompt)
|
||||
|
||||
@@ -2,7 +2,7 @@ import { createMemo } from "solid-js"
|
||||
import { useSync } from "@tui/context/sync"
|
||||
import { Keybind } from "@/util/keybind"
|
||||
import { pipe, mapValues } from "remeda"
|
||||
import type { KeybindsConfig } from "@opencode-ai/sdk"
|
||||
import type { KeybindsConfig } from "@opencode-ai/sdk/v2"
|
||||
import type { ParsedKey, Renderable } from "@opentui/core"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { useKeyboard, useRenderer } from "@opentui/solid"
|
||||
|
||||
@@ -10,12 +10,14 @@ import { createSimpleContext } from "./helper"
|
||||
import { useToast } from "../ui/toast"
|
||||
import { Provider } from "@/provider/provider"
|
||||
import { useArgs } from "./args"
|
||||
import { useSDK } from "./sdk"
|
||||
import { RGBA } from "@opentui/core"
|
||||
|
||||
export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
name: "Local",
|
||||
init: () => {
|
||||
const sync = useSync()
|
||||
const sdk = useSDK()
|
||||
const toast = useToast()
|
||||
|
||||
function isModelValid(model: { providerID: string; modelID: string }) {
|
||||
@@ -310,9 +312,27 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
}
|
||||
})
|
||||
|
||||
const mcp = {
|
||||
isEnabled(name: string) {
|
||||
const status = sync.data.mcp[name]
|
||||
return status?.status === "connected"
|
||||
},
|
||||
async toggle(name: string) {
|
||||
const status = sync.data.mcp[name]
|
||||
if (status?.status === "connected") {
|
||||
// Disable: disconnect the MCP
|
||||
await sdk.client.mcp.disconnect({ name })
|
||||
} else {
|
||||
// Enable/Retry: connect the MCP (handles disabled, failed, and other states)
|
||||
await sdk.client.mcp.connect({ name })
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const result = {
|
||||
model,
|
||||
agent,
|
||||
mcp,
|
||||
}
|
||||
return result
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createOpencodeClient, type Event } from "@opencode-ai/sdk"
|
||||
import { createOpencodeClient, type Event } from "@opencode-ai/sdk/v2"
|
||||
import { createSimpleContext } from "./helper"
|
||||
import { createGlobalEmitter } from "@solid-primitives/event-bus"
|
||||
import { batch, onCleanup, onMount } from "solid-js"
|
||||
@@ -20,9 +20,12 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
|
||||
onMount(async () => {
|
||||
while (true) {
|
||||
if (abort.signal.aborted) break
|
||||
const events = await sdk.event.subscribe({
|
||||
signal: abort.signal,
|
||||
})
|
||||
const events = await sdk.event.subscribe(
|
||||
{},
|
||||
{
|
||||
signal: abort.signal,
|
||||
},
|
||||
)
|
||||
let queue: Event[] = []
|
||||
let timer: Timer | undefined
|
||||
let last = 0
|
||||
|
||||
@@ -15,7 +15,7 @@ import type {
|
||||
ProviderListResponse,
|
||||
ProviderAuthMethod,
|
||||
VcsInfo,
|
||||
} from "@opencode-ai/sdk"
|
||||
} from "@opencode-ai/sdk/v2"
|
||||
import { createStore, produce, reconcile } from "solid-js/store"
|
||||
import { useSDK } from "@tui/context/sdk"
|
||||
import { Binary } from "@opencode-ai/util/binary"
|
||||
@@ -255,19 +255,19 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
async function bootstrap() {
|
||||
// blocking
|
||||
await Promise.all([
|
||||
sdk.client.config.providers({ throwOnError: true }).then((x) => {
|
||||
sdk.client.config.providers({}, { throwOnError: true }).then((x) => {
|
||||
batch(() => {
|
||||
setStore("provider", x.data!.providers)
|
||||
setStore("provider_default", x.data!.default)
|
||||
})
|
||||
}),
|
||||
sdk.client.provider.list({ throwOnError: true }).then((x) => {
|
||||
sdk.client.provider.list({}, { throwOnError: true }).then((x) => {
|
||||
batch(() => {
|
||||
setStore("provider_next", x.data!)
|
||||
})
|
||||
}),
|
||||
sdk.client.app.agents({ throwOnError: true }).then((x) => setStore("agent", x.data ?? [])),
|
||||
sdk.client.config.get({ throwOnError: true }).then((x) => setStore("config", x.data!)),
|
||||
sdk.client.app.agents({}, { throwOnError: true }).then((x) => setStore("agent", x.data ?? [])),
|
||||
sdk.client.config.get({}, { throwOnError: true }).then((x) => setStore("config", x.data!)),
|
||||
])
|
||||
.then(() => {
|
||||
if (store.status !== "complete") setStore("status", "partial")
|
||||
@@ -333,10 +333,10 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
async sync(sessionID: string) {
|
||||
if (fullSyncedSessions.has(sessionID)) return
|
||||
const [session, messages, todo, diff] = await Promise.all([
|
||||
sdk.client.session.get({ path: { id: sessionID }, throwOnError: true }),
|
||||
sdk.client.session.messages({ path: { id: sessionID }, query: { limit: 100 } }),
|
||||
sdk.client.session.todo({ path: { id: sessionID } }),
|
||||
sdk.client.session.diff({ path: { id: sessionID } }),
|
||||
sdk.client.session.get({ sessionID }, { throwOnError: true }),
|
||||
sdk.client.session.messages({ sessionID, limit: 100 }),
|
||||
sdk.client.session.todo({ sessionID }),
|
||||
sdk.client.session.diff({ sessionID }),
|
||||
])
|
||||
setStore(
|
||||
produce((draft) => {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { createSimpleContext } from "./helper"
|
||||
import aura from "./theme/aura.json" with { type: "json" }
|
||||
import ayu from "./theme/ayu.json" with { type: "json" }
|
||||
import catppuccin from "./theme/catppuccin.json" with { type: "json" }
|
||||
import catppuccinMacchiato from "./theme/catppuccin-macchiato.json" with { type: "json" }
|
||||
import cobalt2 from "./theme/cobalt2.json" with { type: "json" }
|
||||
import dracula from "./theme/dracula.json" with { type: "json" }
|
||||
import everforest from "./theme/everforest.json" with { type: "json" }
|
||||
@@ -21,6 +22,7 @@ import nightowl from "./theme/nightowl.json" with { type: "json" }
|
||||
import nord from "./theme/nord.json" with { type: "json" }
|
||||
import onedark from "./theme/one-dark.json" with { type: "json" }
|
||||
import opencode from "./theme/opencode.json" with { type: "json" }
|
||||
import orng from "./theme/orng.json" with { type: "json" }
|
||||
import palenight from "./theme/palenight.json" with { type: "json" }
|
||||
import rosepine from "./theme/rosepine.json" with { type: "json" }
|
||||
import solarized from "./theme/solarized.json" with { type: "json" }
|
||||
@@ -92,6 +94,7 @@ type ThemeColors = {
|
||||
|
||||
type Theme = ThemeColors & {
|
||||
_hasSelectedListItemText: boolean
|
||||
thinkingOpacity: number
|
||||
}
|
||||
|
||||
export function selectedForeground(theme: Theme): RGBA {
|
||||
@@ -124,6 +127,7 @@ type ThemeJson = {
|
||||
theme: Omit<Record<keyof ThemeColors, ColorValue>, "selectedListItemText" | "backgroundMenu"> & {
|
||||
selectedListItemText?: ColorValue
|
||||
backgroundMenu?: ColorValue
|
||||
thinkingOpacity?: number
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +135,7 @@ export const DEFAULT_THEMES: Record<string, ThemeJson> = {
|
||||
aura,
|
||||
ayu,
|
||||
catppuccin,
|
||||
["catppuccin-macchiato"]: catppuccinMacchiato,
|
||||
cobalt2,
|
||||
dracula,
|
||||
everforest,
|
||||
@@ -146,6 +151,7 @@ export const DEFAULT_THEMES: Record<string, ThemeJson> = {
|
||||
nord,
|
||||
["one-dark"]: onedark,
|
||||
opencode,
|
||||
orng,
|
||||
palenight,
|
||||
rosepine,
|
||||
solarized,
|
||||
@@ -181,9 +187,9 @@ function resolveTheme(theme: ThemeJson, mode: "dark" | "light") {
|
||||
|
||||
const resolved = Object.fromEntries(
|
||||
Object.entries(theme.theme)
|
||||
.filter(([key]) => key !== "selectedListItemText" && key !== "backgroundMenu")
|
||||
.filter(([key]) => key !== "selectedListItemText" && key !== "backgroundMenu" && key !== "thinkingOpacity")
|
||||
.map(([key, value]) => {
|
||||
return [key, resolveColor(value)]
|
||||
return [key, resolveColor(value as ColorValue)]
|
||||
}),
|
||||
) as Partial<ThemeColors>
|
||||
|
||||
@@ -204,9 +210,13 @@ function resolveTheme(theme: ThemeJson, mode: "dark" | "light") {
|
||||
resolved.backgroundMenu = resolved.backgroundElement
|
||||
}
|
||||
|
||||
// Handle thinkingOpacity - optional with default of 0.6
|
||||
const thinkingOpacity = theme.theme.thinkingOpacity ?? 0.6
|
||||
|
||||
return {
|
||||
...resolved,
|
||||
_hasSelectedListItemText: hasSelectedListItemText,
|
||||
thinkingOpacity,
|
||||
} as Theme
|
||||
}
|
||||
|
||||
@@ -552,7 +562,7 @@ function generateSubtleSyntax(theme: Theme) {
|
||||
Math.round(fg.r * 255),
|
||||
Math.round(fg.g * 255),
|
||||
Math.round(fg.b * 255),
|
||||
Math.round(0.6 * 255),
|
||||
Math.round(theme.thinkingOpacity * 255),
|
||||
),
|
||||
},
|
||||
}
|
||||
@@ -564,6 +574,12 @@ function generateSubtleSyntax(theme: Theme) {
|
||||
|
||||
function getSyntaxRules(theme: Theme) {
|
||||
return [
|
||||
{
|
||||
scope: ["default"],
|
||||
style: {
|
||||
foreground: theme.text,
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: ["prompt"],
|
||||
style: {
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/theme.json",
|
||||
"defs": {
|
||||
"macRosewater": "#f4dbd6",
|
||||
"macFlamingo": "#f0c6c6",
|
||||
"macPink": "#f5bde6",
|
||||
"macMauve": "#c6a0f6",
|
||||
"macRed": "#ed8796",
|
||||
"macMaroon": "#ee99a0",
|
||||
"macPeach": "#f5a97f",
|
||||
"macYellow": "#eed49f",
|
||||
"macGreen": "#a6da95",
|
||||
"macTeal": "#8bd5ca",
|
||||
"macSky": "#91d7e3",
|
||||
"macSapphire": "#7dc4e4",
|
||||
"macBlue": "#8aadf4",
|
||||
"macLavender": "#b7bdf8",
|
||||
"macText": "#cad3f5",
|
||||
"macSubtext1": "#b8c0e0",
|
||||
"macSubtext0": "#a5adcb",
|
||||
"macOverlay2": "#939ab7",
|
||||
"macOverlay1": "#8087a2",
|
||||
"macOverlay0": "#6e738d",
|
||||
"macSurface2": "#5b6078",
|
||||
"macSurface1": "#494d64",
|
||||
"macSurface0": "#363a4f",
|
||||
"macBase": "#24273a",
|
||||
"macMantle": "#1e2030",
|
||||
"macCrust": "#181926"
|
||||
},
|
||||
"theme": {
|
||||
"primary": {
|
||||
"dark": "macBlue",
|
||||
"light": "macBlue"
|
||||
},
|
||||
"secondary": {
|
||||
"dark": "macMauve",
|
||||
"light": "macMauve"
|
||||
},
|
||||
"accent": {
|
||||
"dark": "macPink",
|
||||
"light": "macPink"
|
||||
},
|
||||
"error": {
|
||||
"dark": "macRed",
|
||||
"light": "macRed"
|
||||
},
|
||||
"warning": {
|
||||
"dark": "macYellow",
|
||||
"light": "macYellow"
|
||||
},
|
||||
"success": {
|
||||
"dark": "macGreen",
|
||||
"light": "macGreen"
|
||||
},
|
||||
"info": {
|
||||
"dark": "macTeal",
|
||||
"light": "macTeal"
|
||||
},
|
||||
"text": {
|
||||
"dark": "macText",
|
||||
"light": "macText"
|
||||
},
|
||||
"textMuted": {
|
||||
"dark": "macSubtext1",
|
||||
"light": "macSubtext1"
|
||||
},
|
||||
"background": {
|
||||
"dark": "macBase",
|
||||
"light": "macBase"
|
||||
},
|
||||
"backgroundPanel": {
|
||||
"dark": "macMantle",
|
||||
"light": "macMantle"
|
||||
},
|
||||
"backgroundElement": {
|
||||
"dark": "macCrust",
|
||||
"light": "macCrust"
|
||||
},
|
||||
"border": {
|
||||
"dark": "macSurface0",
|
||||
"light": "macSurface0"
|
||||
},
|
||||
"borderActive": {
|
||||
"dark": "macSurface1",
|
||||
"light": "macSurface1"
|
||||
},
|
||||
"borderSubtle": {
|
||||
"dark": "macSurface2",
|
||||
"light": "macSurface2"
|
||||
},
|
||||
"diffAdded": {
|
||||
"dark": "macGreen",
|
||||
"light": "macGreen"
|
||||
},
|
||||
"diffRemoved": {
|
||||
"dark": "macRed",
|
||||
"light": "macRed"
|
||||
},
|
||||
"diffContext": {
|
||||
"dark": "macOverlay2",
|
||||
"light": "macOverlay2"
|
||||
},
|
||||
"diffHunkHeader": {
|
||||
"dark": "macPeach",
|
||||
"light": "macPeach"
|
||||
},
|
||||
"diffHighlightAdded": {
|
||||
"dark": "macGreen",
|
||||
"light": "macGreen"
|
||||
},
|
||||
"diffHighlightRemoved": {
|
||||
"dark": "macRed",
|
||||
"light": "macRed"
|
||||
},
|
||||
"diffAddedBg": {
|
||||
"dark": "#29342b",
|
||||
"light": "#29342b"
|
||||
},
|
||||
"diffRemovedBg": {
|
||||
"dark": "#3a2a31",
|
||||
"light": "#3a2a31"
|
||||
},
|
||||
"diffContextBg": {
|
||||
"dark": "macMantle",
|
||||
"light": "macMantle"
|
||||
},
|
||||
"diffLineNumber": {
|
||||
"dark": "macSurface1",
|
||||
"light": "macSurface1"
|
||||
},
|
||||
"diffAddedLineNumberBg": {
|
||||
"dark": "#223025",
|
||||
"light": "#223025"
|
||||
},
|
||||
"diffRemovedLineNumberBg": {
|
||||
"dark": "#2f242b",
|
||||
"light": "#2f242b"
|
||||
},
|
||||
"markdownText": {
|
||||
"dark": "macText",
|
||||
"light": "macText"
|
||||
},
|
||||
"markdownHeading": {
|
||||
"dark": "macMauve",
|
||||
"light": "macMauve"
|
||||
},
|
||||
"markdownLink": {
|
||||
"dark": "macBlue",
|
||||
"light": "macBlue"
|
||||
},
|
||||
"markdownLinkText": {
|
||||
"dark": "macSky",
|
||||
"light": "macSky"
|
||||
},
|
||||
"markdownCode": {
|
||||
"dark": "macGreen",
|
||||
"light": "macGreen"
|
||||
},
|
||||
"markdownBlockQuote": {
|
||||
"dark": "macYellow",
|
||||
"light": "macYellow"
|
||||
},
|
||||
"markdownEmph": {
|
||||
"dark": "macYellow",
|
||||
"light": "macYellow"
|
||||
},
|
||||
"markdownStrong": {
|
||||
"dark": "macPeach",
|
||||
"light": "macPeach"
|
||||
},
|
||||
"markdownHorizontalRule": {
|
||||
"dark": "macSubtext0",
|
||||
"light": "macSubtext0"
|
||||
},
|
||||
"markdownListItem": {
|
||||
"dark": "macBlue",
|
||||
"light": "macBlue"
|
||||
},
|
||||
"markdownListEnumeration": {
|
||||
"dark": "macSky",
|
||||
"light": "macSky"
|
||||
},
|
||||
"markdownImage": {
|
||||
"dark": "macBlue",
|
||||
"light": "macBlue"
|
||||
},
|
||||
"markdownImageText": {
|
||||
"dark": "macSky",
|
||||
"light": "macSky"
|
||||
},
|
||||
"markdownCodeBlock": {
|
||||
"dark": "macText",
|
||||
"light": "macText"
|
||||
},
|
||||
"syntaxComment": {
|
||||
"dark": "macOverlay2",
|
||||
"light": "macOverlay2"
|
||||
},
|
||||
"syntaxKeyword": {
|
||||
"dark": "macMauve",
|
||||
"light": "macMauve"
|
||||
},
|
||||
"syntaxFunction": {
|
||||
"dark": "macBlue",
|
||||
"light": "macBlue"
|
||||
},
|
||||
"syntaxVariable": {
|
||||
"dark": "macRed",
|
||||
"light": "macRed"
|
||||
},
|
||||
"syntaxString": {
|
||||
"dark": "macGreen",
|
||||
"light": "macGreen"
|
||||
},
|
||||
"syntaxNumber": {
|
||||
"dark": "macPeach",
|
||||
"light": "macPeach"
|
||||
},
|
||||
"syntaxType": {
|
||||
"dark": "macYellow",
|
||||
"light": "macYellow"
|
||||
},
|
||||
"syntaxOperator": {
|
||||
"dark": "macSky",
|
||||
"light": "macSky"
|
||||
},
|
||||
"syntaxPunctuation": {
|
||||
"dark": "macText",
|
||||
"light": "macText"
|
||||
}
|
||||
}
|
||||
}
|
||||
245
packages/opencode/src/cli/cmd/tui/context/theme/orng.json
Normal file
@@ -0,0 +1,245 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/theme.json",
|
||||
"defs": {
|
||||
"darkStep1": "#0a0a0a",
|
||||
"darkStep2": "#141414",
|
||||
"darkStep3": "#1e1e1e",
|
||||
"darkStep4": "#282828",
|
||||
"darkStep5": "#323232",
|
||||
"darkStep6": "#3c3c3c",
|
||||
"darkStep7": "#484848",
|
||||
"darkStep8": "#606060",
|
||||
"darkStep9": "#EC5B2B",
|
||||
"darkStep10": "#EE7948",
|
||||
"darkStep11": "#808080",
|
||||
"darkStep12": "#eeeeee",
|
||||
"darkSecondary": "#EE7948",
|
||||
"darkAccent": "#FFF7F1",
|
||||
"darkRed": "#e06c75",
|
||||
"darkOrange": "#EC5B2B",
|
||||
"darkGreen": "#7fd88f",
|
||||
"darkCyan": "#56b6c2",
|
||||
"darkYellow": "#e5c07b",
|
||||
"lightStep1": "#ffffff",
|
||||
"lightStep2": "#FFF7F1",
|
||||
"lightStep3": "#f5f0eb",
|
||||
"lightStep4": "#ebebeb",
|
||||
"lightStep5": "#e1e1e1",
|
||||
"lightStep6": "#d4d4d4",
|
||||
"lightStep7": "#b8b8b8",
|
||||
"lightStep8": "#a0a0a0",
|
||||
"lightStep9": "#EC5B2B",
|
||||
"lightStep10": "#c94d24",
|
||||
"lightStep11": "#8a8a8a",
|
||||
"lightStep12": "#1a1a1a",
|
||||
"lightSecondary": "#EE7948",
|
||||
"lightAccent": "#c94d24",
|
||||
"lightRed": "#d1383d",
|
||||
"lightOrange": "#EC5B2B",
|
||||
"lightGreen": "#3d9a57",
|
||||
"lightCyan": "#318795",
|
||||
"lightYellow": "#b0851f"
|
||||
},
|
||||
"theme": {
|
||||
"primary": {
|
||||
"dark": "darkStep9",
|
||||
"light": "lightStep9"
|
||||
},
|
||||
"secondary": {
|
||||
"dark": "darkSecondary",
|
||||
"light": "lightSecondary"
|
||||
},
|
||||
"accent": {
|
||||
"dark": "darkAccent",
|
||||
"light": "lightAccent"
|
||||
},
|
||||
"error": {
|
||||
"dark": "darkRed",
|
||||
"light": "lightRed"
|
||||
},
|
||||
"warning": {
|
||||
"dark": "darkOrange",
|
||||
"light": "lightOrange"
|
||||
},
|
||||
"success": {
|
||||
"dark": "darkGreen",
|
||||
"light": "lightGreen"
|
||||
},
|
||||
"info": {
|
||||
"dark": "darkCyan",
|
||||
"light": "lightCyan"
|
||||
},
|
||||
"text": {
|
||||
"dark": "darkStep12",
|
||||
"light": "lightStep12"
|
||||
},
|
||||
"textMuted": {
|
||||
"dark": "darkStep11",
|
||||
"light": "lightStep11"
|
||||
},
|
||||
"background": {
|
||||
"dark": "darkStep1",
|
||||
"light": "lightStep1"
|
||||
},
|
||||
"backgroundPanel": {
|
||||
"dark": "darkStep2",
|
||||
"light": "lightStep2"
|
||||
},
|
||||
"backgroundElement": {
|
||||
"dark": "darkStep3",
|
||||
"light": "lightStep3"
|
||||
},
|
||||
"border": {
|
||||
"dark": "#EC5B2B",
|
||||
"light": "#EC5B2B"
|
||||
},
|
||||
"borderActive": {
|
||||
"dark": "#EE7948",
|
||||
"light": "#c94d24"
|
||||
},
|
||||
"borderSubtle": {
|
||||
"dark": "darkStep6",
|
||||
"light": "lightStep6"
|
||||
},
|
||||
"diffAdded": {
|
||||
"dark": "#4fd6be",
|
||||
"light": "#1e725c"
|
||||
},
|
||||
"diffRemoved": {
|
||||
"dark": "#c53b53",
|
||||
"light": "#c53b53"
|
||||
},
|
||||
"diffContext": {
|
||||
"dark": "#828bb8",
|
||||
"light": "#7086b5"
|
||||
},
|
||||
"diffHunkHeader": {
|
||||
"dark": "#828bb8",
|
||||
"light": "#7086b5"
|
||||
},
|
||||
"diffHighlightAdded": {
|
||||
"dark": "#b8db87",
|
||||
"light": "#4db380"
|
||||
},
|
||||
"diffHighlightRemoved": {
|
||||
"dark": "#e26a75",
|
||||
"light": "#f52a65"
|
||||
},
|
||||
"diffAddedBg": {
|
||||
"dark": "#20303b",
|
||||
"light": "#d5e5d5"
|
||||
},
|
||||
"diffRemovedBg": {
|
||||
"dark": "#37222c",
|
||||
"light": "#f7d8db"
|
||||
},
|
||||
"diffContextBg": {
|
||||
"dark": "darkStep2",
|
||||
"light": "lightStep2"
|
||||
},
|
||||
"diffLineNumber": {
|
||||
"dark": "darkStep3",
|
||||
"light": "lightStep3"
|
||||
},
|
||||
"diffAddedLineNumberBg": {
|
||||
"dark": "#1b2b34",
|
||||
"light": "#c5d5c5"
|
||||
},
|
||||
"diffRemovedLineNumberBg": {
|
||||
"dark": "#2d1f26",
|
||||
"light": "#e7c8cb"
|
||||
},
|
||||
"markdownText": {
|
||||
"dark": "darkStep12",
|
||||
"light": "lightStep12"
|
||||
},
|
||||
"markdownHeading": {
|
||||
"dark": "#EC5B2B",
|
||||
"light": "#EC5B2B"
|
||||
},
|
||||
"markdownLink": {
|
||||
"dark": "darkStep9",
|
||||
"light": "lightStep9"
|
||||
},
|
||||
"markdownLinkText": {
|
||||
"dark": "darkCyan",
|
||||
"light": "lightCyan"
|
||||
},
|
||||
"markdownCode": {
|
||||
"dark": "darkGreen",
|
||||
"light": "lightGreen"
|
||||
},
|
||||
"markdownBlockQuote": {
|
||||
"dark": "#FFF7F1",
|
||||
"light": "lightYellow"
|
||||
},
|
||||
"markdownEmph": {
|
||||
"dark": "darkYellow",
|
||||
"light": "lightYellow"
|
||||
},
|
||||
"markdownStrong": {
|
||||
"dark": "#EE7948",
|
||||
"light": "#EC5B2B"
|
||||
},
|
||||
"markdownHorizontalRule": {
|
||||
"dark": "darkStep11",
|
||||
"light": "lightStep11"
|
||||
},
|
||||
"markdownListItem": {
|
||||
"dark": "darkStep9",
|
||||
"light": "lightStep9"
|
||||
},
|
||||
"markdownListEnumeration": {
|
||||
"dark": "darkCyan",
|
||||
"light": "lightCyan"
|
||||
},
|
||||
"markdownImage": {
|
||||
"dark": "darkStep9",
|
||||
"light": "lightStep9"
|
||||
},
|
||||
"markdownImageText": {
|
||||
"dark": "darkCyan",
|
||||
"light": "lightCyan"
|
||||
},
|
||||
"markdownCodeBlock": {
|
||||
"dark": "darkStep12",
|
||||
"light": "lightStep12"
|
||||
},
|
||||
"syntaxComment": {
|
||||
"dark": "darkStep11",
|
||||
"light": "lightStep11"
|
||||
},
|
||||
"syntaxKeyword": {
|
||||
"dark": "#EC5B2B",
|
||||
"light": "#EC5B2B"
|
||||
},
|
||||
"syntaxFunction": {
|
||||
"dark": "#EE7948",
|
||||
"light": "#c94d24"
|
||||
},
|
||||
"syntaxVariable": {
|
||||
"dark": "darkRed",
|
||||
"light": "lightRed"
|
||||
},
|
||||
"syntaxString": {
|
||||
"dark": "darkGreen",
|
||||
"light": "lightGreen"
|
||||
},
|
||||
"syntaxNumber": {
|
||||
"dark": "#FFF7F1",
|
||||
"light": "#EC5B2B"
|
||||
},
|
||||
"syntaxType": {
|
||||
"dark": "darkYellow",
|
||||
"light": "lightYellow"
|
||||
},
|
||||
"syntaxOperator": {
|
||||
"dark": "darkCyan",
|
||||
"light": "lightCyan"
|
||||
},
|
||||
"syntaxPunctuation": {
|
||||
"dark": "darkStep12",
|
||||
"light": "lightStep12"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,12 @@ export function Home() {
|
||||
return Object.values(sync.data.mcp).some((x) => x.status === "failed")
|
||||
})
|
||||
|
||||
const connectedMcpCount = createMemo(() => {
|
||||
return Object.values(sync.data.mcp).filter((x) => x.status === "connected").length
|
||||
})
|
||||
|
||||
const Hint = (
|
||||
<Show when={Object.keys(sync.data.mcp).length > 0}>
|
||||
<Show when={connectedMcpCount() > 0}>
|
||||
<box flexShrink={0} flexDirection="row" gap={1}>
|
||||
<text fg={theme.text}>
|
||||
<Switch>
|
||||
@@ -35,7 +39,7 @@ export function Home() {
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<span style={{ fg: theme.success }}>•</span>{" "}
|
||||
{Locale.pluralize(Object.values(sync.data.mcp).length, "{} mcp server", "{} mcp servers")}
|
||||
{Locale.pluralize(connectedMcpCount(), "{} mcp server", "{} mcp servers")}
|
||||
</Match>
|
||||
</Switch>
|
||||
</text>
|
||||
@@ -85,7 +89,7 @@ export function Home() {
|
||||
<span style={{ fg: theme.success }}>⊙ </span>
|
||||
</Match>
|
||||
</Switch>
|
||||
{Object.keys(sync.data.mcp).length} MCP
|
||||
{connectedMcpCount()} MCP
|
||||
</text>
|
||||
<text fg={theme.textMuted}>/status</text>
|
||||
</Show>
|
||||
|
||||
@@ -29,12 +29,8 @@ export function DialogMessage(props: {
|
||||
if (!msg) return
|
||||
|
||||
sdk.client.session.revert({
|
||||
path: {
|
||||
id: props.sessionID,
|
||||
},
|
||||
body: {
|
||||
messageID: msg.id,
|
||||
},
|
||||
sessionID: props.sessionID,
|
||||
messageID: msg.id,
|
||||
})
|
||||
|
||||
if (props.setPrompt) {
|
||||
@@ -81,12 +77,8 @@ export function DialogMessage(props: {
|
||||
description: "create a new session",
|
||||
onSelect: async (dialog) => {
|
||||
const result = await sdk.client.session.fork({
|
||||
path: {
|
||||
id: props.sessionID,
|
||||
},
|
||||
body: {
|
||||
messageID: props.messageID,
|
||||
},
|
||||
sessionID: props.sessionID,
|
||||
messageID: props.messageID,
|
||||
})
|
||||
route.navigate({
|
||||
sessionID: result.data!.id,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createMemo, onMount } from "solid-js"
|
||||
import { useSync } from "@tui/context/sync"
|
||||
import { DialogSelect, type DialogSelectOption } from "@tui/ui/dialog-select"
|
||||
import type { TextPart } from "@opencode-ai/sdk"
|
||||
import type { TextPart } from "@opencode-ai/sdk/v2"
|
||||
import { Locale } from "@/util/locale"
|
||||
import { DialogMessage } from "./dialog-message"
|
||||
import { useDialog } from "../../ui/dialog"
|
||||
|
||||
@@ -4,13 +4,19 @@ import { useSync } from "../../context/sync"
|
||||
import { useDirectory } from "../../context/directory"
|
||||
import { useConnected } from "../../component/dialog-model"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { useRoute } from "../../context/route"
|
||||
|
||||
export function Footer() {
|
||||
const { theme } = useTheme()
|
||||
const sync = useSync()
|
||||
const route = useRoute()
|
||||
const mcp = createMemo(() => Object.keys(sync.data.mcp))
|
||||
const mcpError = createMemo(() => Object.values(sync.data.mcp).some((x) => x.status === "failed"))
|
||||
const lsp = createMemo(() => Object.keys(sync.data.lsp))
|
||||
const permissions = createMemo(() => {
|
||||
if (route.data.type !== "session") return []
|
||||
return sync.data.permission[route.data.sessionID] ?? []
|
||||
})
|
||||
const directory = useDirectory()
|
||||
const connected = useConnected()
|
||||
|
||||
@@ -51,6 +57,12 @@ export function Footer() {
|
||||
</text>
|
||||
</Match>
|
||||
<Match when={connected()}>
|
||||
<Show when={permissions().length > 0}>
|
||||
<text fg={theme.warning}>
|
||||
<span style={{ fg: theme.warning }}>◉</span> {permissions().length} Permission
|
||||
{permissions().length > 1 ? "s" : ""}
|
||||
</text>
|
||||
</Show>
|
||||
<text fg={theme.text}>
|
||||
<span style={{ fg: theme.success }}>•</span> {lsp().length} LSP
|
||||
</text>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useSync } from "@tui/context/sync"
|
||||
import { pipe, sumBy } from "remeda"
|
||||
import { useTheme } from "@tui/context/theme"
|
||||
import { SplitBorder, EmptyBorder } from "@tui/component/border"
|
||||
import type { AssistantMessage, Session } from "@opencode-ai/sdk"
|
||||
import type { AssistantMessage, Session } from "@opencode-ai/sdk/v2"
|
||||
import { useDirectory } from "../../context/directory"
|
||||
import { useKeybind } from "../../context/keybind"
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
type ScrollAcceleration,
|
||||
} from "@opentui/core"
|
||||
import { Prompt, type PromptRef } from "@tui/component/prompt"
|
||||
import type { AssistantMessage, Part, ToolPart, UserMessage, TextPart, ReasoningPart } from "@opencode-ai/sdk"
|
||||
import type { AssistantMessage, Part, ToolPart, UserMessage, TextPart, ReasoningPart } from "@opencode-ai/sdk/v2"
|
||||
import { useLocal } from "@tui/context/local"
|
||||
import { Locale } from "@/util/locale"
|
||||
import type { Tool } from "@/tool/tool"
|
||||
@@ -150,7 +150,8 @@ export function Session() {
|
||||
.then(() => {
|
||||
if (scroll) scroll.scrollBy(100_000)
|
||||
})
|
||||
.catch(() => {
|
||||
.catch((e) => {
|
||||
console.error(e)
|
||||
toast.show({
|
||||
message: `Session not found: ${route.sessionID}`,
|
||||
variant: "error",
|
||||
@@ -202,14 +203,10 @@ export function Session() {
|
||||
return
|
||||
})
|
||||
if (response) {
|
||||
sdk.client.postSessionIdPermissionsPermissionId({
|
||||
path: {
|
||||
permissionID: first.id,
|
||||
id: route.sessionID,
|
||||
},
|
||||
body: {
|
||||
response: response,
|
||||
},
|
||||
sdk.client.permission.respond({
|
||||
permissionID: first.id,
|
||||
sessionID: route.sessionID,
|
||||
response: response,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -254,9 +251,7 @@ export function Session() {
|
||||
onSelect: async (dialog: any) => {
|
||||
await sdk.client.session
|
||||
.share({
|
||||
path: {
|
||||
id: route.sessionID,
|
||||
},
|
||||
sessionID: route.sessionID,
|
||||
})
|
||||
.then((res) =>
|
||||
Clipboard.copy(res.data!.share!.url).catch(() =>
|
||||
@@ -314,13 +309,9 @@ export function Session() {
|
||||
return
|
||||
}
|
||||
sdk.client.session.summarize({
|
||||
path: {
|
||||
id: route.sessionID,
|
||||
},
|
||||
body: {
|
||||
modelID: selectedModel.modelID,
|
||||
providerID: selectedModel.providerID,
|
||||
},
|
||||
sessionID: route.sessionID,
|
||||
modelID: selectedModel.modelID,
|
||||
providerID: selectedModel.providerID,
|
||||
})
|
||||
dialog.clear()
|
||||
},
|
||||
@@ -333,9 +324,7 @@ export function Session() {
|
||||
category: "Session",
|
||||
onSelect: (dialog) => {
|
||||
sdk.client.session.unshare({
|
||||
path: {
|
||||
id: route.sessionID,
|
||||
},
|
||||
sessionID: route.sessionID,
|
||||
})
|
||||
dialog.clear()
|
||||
},
|
||||
@@ -347,18 +336,14 @@ export function Session() {
|
||||
category: "Session",
|
||||
onSelect: async (dialog) => {
|
||||
const status = sync.data.session_status[route.sessionID]
|
||||
if (status?.type !== "idle") await sdk.client.session.abort({ path: { id: route.sessionID } }).catch(() => {})
|
||||
if (status?.type !== "idle") await sdk.client.session.abort({ sessionID: route.sessionID }).catch(() => {})
|
||||
const revert = session().revert?.messageID
|
||||
const message = messages().findLast((x) => (!revert || x.id < revert) && x.role === "user")
|
||||
if (!message) return
|
||||
sdk.client.session
|
||||
.revert({
|
||||
path: {
|
||||
id: route.sessionID,
|
||||
},
|
||||
body: {
|
||||
messageID: message.id,
|
||||
},
|
||||
sessionID: route.sessionID,
|
||||
messageID: message.id,
|
||||
})
|
||||
.then(() => {
|
||||
toBottom()
|
||||
@@ -392,20 +377,14 @@ export function Session() {
|
||||
const message = messages().find((x) => x.role === "user" && x.id > messageID)
|
||||
if (!message) {
|
||||
sdk.client.session.unrevert({
|
||||
path: {
|
||||
id: route.sessionID,
|
||||
},
|
||||
sessionID: route.sessionID,
|
||||
})
|
||||
prompt.set({ input: "", parts: [] })
|
||||
return
|
||||
}
|
||||
sdk.client.session.revert({
|
||||
path: {
|
||||
id: route.sessionID,
|
||||
},
|
||||
body: {
|
||||
messageID: message.id,
|
||||
},
|
||||
sessionID: route.sessionID,
|
||||
messageID: message.id,
|
||||
})
|
||||
},
|
||||
},
|
||||
@@ -1066,16 +1045,16 @@ function UserMessage(props: {
|
||||
</box>
|
||||
</Show>
|
||||
<text fg={theme.textMuted}>
|
||||
{ctx.usernameVisible() ? `${sync.data.config.username ?? "You"}` : "You"}
|
||||
{ctx.usernameVisible() ? `${sync.data.config.username ?? "You "}` : "You "}
|
||||
<Show
|
||||
when={queued()}
|
||||
fallback={
|
||||
<span style={{ fg: theme.textMuted }}>
|
||||
{ctx.usernameVisible() ? " · " : " "}
|
||||
{ctx.showTimestamps()
|
||||
? Locale.todayTimeOrDateTime(props.message.time.created)
|
||||
: Locale.time(props.message.time.created)}
|
||||
</span>
|
||||
<Show when={ctx.showTimestamps()}>
|
||||
<span style={{ fg: theme.textMuted }}>
|
||||
{ctx.usernameVisible() ? " · " : " "}
|
||||
{Locale.todayTimeOrDateTime(props.message.time.created)}
|
||||
</span>
|
||||
</Show>
|
||||
}
|
||||
>
|
||||
<span style={{ bg: theme.accent, fg: theme.backgroundPanel, bold: true }}> QUEUED </span>
|
||||
@@ -1621,6 +1600,7 @@ ToolRegistry.register<typeof EditTool>({
|
||||
showLineNumbers={true}
|
||||
width="100%"
|
||||
wrapMode={ctx.diffWrapMode()}
|
||||
fg={theme.text}
|
||||
addedBg={theme.diffAddedBg}
|
||||
removedBg={theme.diffRemovedBg}
|
||||
contextBg={theme.diffContextBg}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { createStore } from "solid-js/store"
|
||||
import { useTheme } from "../../context/theme"
|
||||
import { Locale } from "@/util/locale"
|
||||
import path from "path"
|
||||
import type { AssistantMessage } from "@opencode-ai/sdk"
|
||||
import type { AssistantMessage } from "@opencode-ai/sdk/v2"
|
||||
import { Global } from "@/global"
|
||||
import { Installation } from "@/installation"
|
||||
import { useKeybind } from "../../context/keybind"
|
||||
@@ -104,11 +104,15 @@ export function Sidebar(props: { sessionID: string }) {
|
||||
<text
|
||||
flexShrink={0}
|
||||
style={{
|
||||
fg: {
|
||||
connected: theme.success,
|
||||
failed: theme.error,
|
||||
disabled: theme.textMuted,
|
||||
}[item.status],
|
||||
fg: (
|
||||
{
|
||||
connected: theme.success,
|
||||
failed: theme.error,
|
||||
disabled: theme.textMuted,
|
||||
needs_auth: theme.warning,
|
||||
needs_client_registration: theme.error,
|
||||
} as Record<string, typeof theme.success>
|
||||
)[item.status],
|
||||
}}
|
||||
>
|
||||
•
|
||||
@@ -116,10 +120,14 @@ export function Sidebar(props: { sessionID: string }) {
|
||||
<text fg={theme.text} wrapMode="word">
|
||||
{key}{" "}
|
||||
<span style={{ fg: theme.textMuted }}>
|
||||
<Switch>
|
||||
<Switch fallback={item.status}>
|
||||
<Match when={item.status === "connected"}>Connected</Match>
|
||||
<Match when={item.status === "failed" && item}>{(val) => <i>{val().error}</i>}</Match>
|
||||
<Match when={item.status === "disabled"}>Disabled in configuration</Match>
|
||||
<Match when={item.status === "disabled"}>Disabled</Match>
|
||||
<Match when={(item.status as string) === "needs_auth"}>Needs auth</Match>
|
||||
<Match when={(item.status as string) === "needs_client_registration"}>
|
||||
Needs client ID
|
||||
</Match>
|
||||
</Switch>
|
||||
</span>
|
||||
</text>
|
||||
@@ -240,7 +248,7 @@ export function Sidebar(props: { sessionID: string }) {
|
||||
</box>
|
||||
</scrollbox>
|
||||
|
||||
<box flexShrink={0} gap={1}>
|
||||
<box flexShrink={0} gap={1} paddingTop={1}>
|
||||
<Show when={!hasProviders()}>
|
||||
<box
|
||||
backgroundColor={theme.backgroundElement}
|
||||
@@ -267,7 +275,7 @@ export function Sidebar(props: { sessionID: string }) {
|
||||
</box>
|
||||
</box>
|
||||
</Show>
|
||||
<text fg={theme.textMuted}>{directory()}</text>
|
||||
<text fg={theme.text}>{directory()}</text>
|
||||
<text fg={theme.textMuted}>
|
||||
<span style={{ fg: theme.success }}>•</span> <b>Open</b>
|
||||
<span style={{ fg: theme.text }}>
|
||||
|
||||
@@ -60,7 +60,6 @@ export const TuiThreadCommand = cmd({
|
||||
const cwd = args.project ? path.resolve(baseCwd, args.project) : process.cwd()
|
||||
const localWorker = new URL("./worker.ts", import.meta.url)
|
||||
const distWorker = new URL("./cli/cmd/tui/worker.js", import.meta.url)
|
||||
const execDir = path.dirname(process.execPath)
|
||||
const workerPath = await iife(async () => {
|
||||
if (typeof OPENCODE_WORKER_PATH !== "undefined") return OPENCODE_WORKER_PATH
|
||||
if (await Bun.file(distWorker).exists()) return distWorker
|
||||
|
||||
@@ -49,6 +49,9 @@ export function DialogPrompt(props: DialogPromptProps) {
|
||||
ref={(val: TextareaRenderable) => (textarea = val)}
|
||||
initialValue={props.value}
|
||||
placeholder={props.placeholder ?? "Enter text"}
|
||||
textColor={theme.text}
|
||||
focusedTextColor={theme.text}
|
||||
cursorColor={theme.text}
|
||||
/>
|
||||
</box>
|
||||
<box paddingBottom={1} gap={1} flexDirection="row">
|
||||
|
||||
344
packages/opencode/src/cli/cmd/uninstall.ts
Normal file
@@ -0,0 +1,344 @@
|
||||
import type { Argv } from "yargs"
|
||||
import { UI } from "../ui"
|
||||
import * as prompts from "@clack/prompts"
|
||||
import { Installation } from "../../installation"
|
||||
import { Global } from "../../global"
|
||||
import { $ } from "bun"
|
||||
import fs from "fs/promises"
|
||||
import path from "path"
|
||||
import os from "os"
|
||||
|
||||
interface UninstallArgs {
|
||||
keepConfig: boolean
|
||||
keepData: boolean
|
||||
dryRun: boolean
|
||||
force: boolean
|
||||
}
|
||||
|
||||
interface RemovalTargets {
|
||||
directories: Array<{ path: string; label: string; keep: boolean }>
|
||||
shellConfig: string | null
|
||||
binary: string | null
|
||||
}
|
||||
|
||||
export const UninstallCommand = {
|
||||
command: "uninstall",
|
||||
describe: "uninstall opencode and remove all related files",
|
||||
builder: (yargs: Argv) =>
|
||||
yargs
|
||||
.option("keep-config", {
|
||||
alias: "c",
|
||||
type: "boolean",
|
||||
describe: "keep configuration files",
|
||||
default: false,
|
||||
})
|
||||
.option("keep-data", {
|
||||
alias: "d",
|
||||
type: "boolean",
|
||||
describe: "keep session data and snapshots",
|
||||
default: false,
|
||||
})
|
||||
.option("dry-run", {
|
||||
type: "boolean",
|
||||
describe: "show what would be removed without removing",
|
||||
default: false,
|
||||
})
|
||||
.option("force", {
|
||||
alias: "f",
|
||||
type: "boolean",
|
||||
describe: "skip confirmation prompts",
|
||||
default: false,
|
||||
}),
|
||||
|
||||
handler: async (args: UninstallArgs) => {
|
||||
UI.empty()
|
||||
UI.println(UI.logo(" "))
|
||||
UI.empty()
|
||||
prompts.intro("Uninstall OpenCode")
|
||||
|
||||
const method = await Installation.method()
|
||||
prompts.log.info(`Installation method: ${method}`)
|
||||
|
||||
const targets = await collectRemovalTargets(args, method)
|
||||
|
||||
await showRemovalSummary(targets, method)
|
||||
|
||||
if (!args.force && !args.dryRun) {
|
||||
const confirm = await prompts.confirm({
|
||||
message: "Are you sure you want to uninstall?",
|
||||
initialValue: false,
|
||||
})
|
||||
if (!confirm || prompts.isCancel(confirm)) {
|
||||
prompts.outro("Cancelled")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (args.dryRun) {
|
||||
prompts.log.warn("Dry run - no changes made")
|
||||
prompts.outro("Done")
|
||||
return
|
||||
}
|
||||
|
||||
await executeUninstall(method, targets)
|
||||
|
||||
prompts.outro("Done")
|
||||
},
|
||||
}
|
||||
|
||||
async function collectRemovalTargets(args: UninstallArgs, method: Installation.Method): Promise<RemovalTargets> {
|
||||
const directories: RemovalTargets["directories"] = [
|
||||
{ path: Global.Path.data, label: "Data", keep: args.keepData },
|
||||
{ path: Global.Path.cache, label: "Cache", keep: false },
|
||||
{ path: Global.Path.config, label: "Config", keep: args.keepConfig },
|
||||
{ path: Global.Path.state, label: "State", keep: false },
|
||||
]
|
||||
|
||||
const shellConfig = method === "curl" ? await getShellConfigFile() : null
|
||||
const binary = method === "curl" ? process.execPath : null
|
||||
|
||||
return { directories, shellConfig, binary }
|
||||
}
|
||||
|
||||
async function showRemovalSummary(targets: RemovalTargets, method: Installation.Method) {
|
||||
prompts.log.message("The following will be removed:")
|
||||
|
||||
for (const dir of targets.directories) {
|
||||
const exists = await fs
|
||||
.access(dir.path)
|
||||
.then(() => true)
|
||||
.catch(() => false)
|
||||
if (!exists) continue
|
||||
|
||||
const size = await getDirectorySize(dir.path)
|
||||
const sizeStr = formatSize(size)
|
||||
const status = dir.keep ? UI.Style.TEXT_DIM + "(keeping)" : ""
|
||||
const prefix = dir.keep ? "○" : "✓"
|
||||
|
||||
prompts.log.info(` ${prefix} ${dir.label}: ${shortenPath(dir.path)} ${UI.Style.TEXT_DIM}(${sizeStr})${status}`)
|
||||
}
|
||||
|
||||
if (targets.binary) {
|
||||
prompts.log.info(` ✓ Binary: ${shortenPath(targets.binary)}`)
|
||||
}
|
||||
|
||||
if (targets.shellConfig) {
|
||||
prompts.log.info(` ✓ Shell PATH in ${shortenPath(targets.shellConfig)}`)
|
||||
}
|
||||
|
||||
if (method !== "curl" && method !== "unknown") {
|
||||
const cmds: Record<string, string> = {
|
||||
npm: "npm uninstall -g opencode-ai",
|
||||
pnpm: "pnpm uninstall -g opencode-ai",
|
||||
bun: "bun remove -g opencode-ai",
|
||||
yarn: "yarn global remove opencode-ai",
|
||||
brew: "brew uninstall opencode",
|
||||
}
|
||||
prompts.log.info(` ✓ Package: ${cmds[method] || method}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function executeUninstall(method: Installation.Method, targets: RemovalTargets) {
|
||||
const spinner = prompts.spinner()
|
||||
const errors: string[] = []
|
||||
|
||||
for (const dir of targets.directories) {
|
||||
if (dir.keep) {
|
||||
prompts.log.step(`Skipping ${dir.label} (--keep-${dir.label.toLowerCase()})`)
|
||||
continue
|
||||
}
|
||||
|
||||
const exists = await fs
|
||||
.access(dir.path)
|
||||
.then(() => true)
|
||||
.catch(() => false)
|
||||
if (!exists) continue
|
||||
|
||||
spinner.start(`Removing ${dir.label}...`)
|
||||
const err = await fs.rm(dir.path, { recursive: true, force: true }).catch((e) => e)
|
||||
if (err) {
|
||||
spinner.stop(`Failed to remove ${dir.label}`, 1)
|
||||
errors.push(`${dir.label}: ${err.message}`)
|
||||
continue
|
||||
}
|
||||
spinner.stop(`Removed ${dir.label}`)
|
||||
}
|
||||
|
||||
if (targets.shellConfig) {
|
||||
spinner.start("Cleaning shell config...")
|
||||
const err = await cleanShellConfig(targets.shellConfig).catch((e) => e)
|
||||
if (err) {
|
||||
spinner.stop("Failed to clean shell config", 1)
|
||||
errors.push(`Shell config: ${err.message}`)
|
||||
} else {
|
||||
spinner.stop("Cleaned shell config")
|
||||
}
|
||||
}
|
||||
|
||||
if (method !== "curl" && method !== "unknown") {
|
||||
const cmds: Record<string, string[]> = {
|
||||
npm: ["npm", "uninstall", "-g", "opencode-ai"],
|
||||
pnpm: ["pnpm", "uninstall", "-g", "opencode-ai"],
|
||||
bun: ["bun", "remove", "-g", "opencode-ai"],
|
||||
yarn: ["yarn", "global", "remove", "opencode-ai"],
|
||||
brew: ["brew", "uninstall", "opencode"],
|
||||
}
|
||||
|
||||
const cmd = cmds[method]
|
||||
if (cmd) {
|
||||
spinner.start(`Running ${cmd.join(" ")}...`)
|
||||
const result = await $`${cmd}`.quiet().nothrow()
|
||||
if (result.exitCode !== 0) {
|
||||
spinner.stop(`Package manager uninstall failed`, 1)
|
||||
prompts.log.warn(`You may need to run manually: ${cmd.join(" ")}`)
|
||||
errors.push(`Package manager: exit code ${result.exitCode}`)
|
||||
} else {
|
||||
spinner.stop("Package removed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (method === "curl" && targets.binary) {
|
||||
UI.empty()
|
||||
prompts.log.message("To finish removing the binary, run:")
|
||||
prompts.log.info(` rm "${targets.binary}"`)
|
||||
|
||||
const binDir = path.dirname(targets.binary)
|
||||
if (binDir.includes(".opencode")) {
|
||||
prompts.log.info(` rmdir "${binDir}" 2>/dev/null`)
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
UI.empty()
|
||||
prompts.log.warn("Some operations failed:")
|
||||
for (const err of errors) {
|
||||
prompts.log.error(` ${err}`)
|
||||
}
|
||||
}
|
||||
|
||||
UI.empty()
|
||||
prompts.log.success("Thank you for using OpenCode!")
|
||||
}
|
||||
|
||||
async function getShellConfigFile(): Promise<string | null> {
|
||||
const shell = path.basename(process.env.SHELL || "bash")
|
||||
const home = os.homedir()
|
||||
const xdgConfig = process.env.XDG_CONFIG_HOME || path.join(home, ".config")
|
||||
|
||||
const configFiles: Record<string, string[]> = {
|
||||
fish: [path.join(xdgConfig, "fish", "config.fish")],
|
||||
zsh: [
|
||||
path.join(home, ".zshrc"),
|
||||
path.join(home, ".zshenv"),
|
||||
path.join(xdgConfig, "zsh", ".zshrc"),
|
||||
path.join(xdgConfig, "zsh", ".zshenv"),
|
||||
],
|
||||
bash: [
|
||||
path.join(home, ".bashrc"),
|
||||
path.join(home, ".bash_profile"),
|
||||
path.join(home, ".profile"),
|
||||
path.join(xdgConfig, "bash", ".bashrc"),
|
||||
path.join(xdgConfig, "bash", ".bash_profile"),
|
||||
],
|
||||
ash: [path.join(home, ".ashrc"), path.join(home, ".profile")],
|
||||
sh: [path.join(home, ".profile")],
|
||||
}
|
||||
|
||||
const candidates = configFiles[shell] || configFiles.bash
|
||||
|
||||
for (const file of candidates) {
|
||||
const exists = await fs
|
||||
.access(file)
|
||||
.then(() => true)
|
||||
.catch(() => false)
|
||||
if (!exists) continue
|
||||
|
||||
const content = await Bun.file(file)
|
||||
.text()
|
||||
.catch(() => "")
|
||||
if (content.includes("# opencode") || content.includes(".opencode/bin")) {
|
||||
return file
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async function cleanShellConfig(file: string) {
|
||||
const content = await Bun.file(file).text()
|
||||
const lines = content.split("\n")
|
||||
|
||||
const filtered: string[] = []
|
||||
let skip = false
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim()
|
||||
|
||||
if (trimmed === "# opencode") {
|
||||
skip = true
|
||||
continue
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
skip = false
|
||||
if (trimmed.includes(".opencode/bin") || trimmed.includes("fish_add_path")) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
(trimmed.startsWith("export PATH=") && trimmed.includes(".opencode/bin")) ||
|
||||
(trimmed.startsWith("fish_add_path") && trimmed.includes(".opencode"))
|
||||
) {
|
||||
continue
|
||||
}
|
||||
|
||||
filtered.push(line)
|
||||
}
|
||||
|
||||
while (filtered.length > 0 && filtered[filtered.length - 1].trim() === "") {
|
||||
filtered.pop()
|
||||
}
|
||||
|
||||
const output = filtered.join("\n") + "\n"
|
||||
await Bun.write(file, output)
|
||||
}
|
||||
|
||||
async function getDirectorySize(dir: string): Promise<number> {
|
||||
let total = 0
|
||||
|
||||
const walk = async (current: string) => {
|
||||
const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => [])
|
||||
|
||||
for (const entry of entries) {
|
||||
const full = path.join(current, entry.name)
|
||||
if (entry.isDirectory()) {
|
||||
await walk(full)
|
||||
continue
|
||||
}
|
||||
if (entry.isFile()) {
|
||||
const stat = await fs.stat(full).catch(() => null)
|
||||
if (stat) total += stat.size
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await walk(dir)
|
||||
return total
|
||||
}
|
||||
|
||||
function formatSize(bytes: number): string {
|
||||
if (bytes < 1024) return `${bytes} B`
|
||||
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
|
||||
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
|
||||
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`
|
||||
}
|
||||
|
||||
function shortenPath(p: string): string {
|
||||
const home = os.homedir()
|
||||
if (p.startsWith(home)) {
|
||||
return p.replace(home, "~")
|
||||
}
|
||||
return p
|
||||
}
|
||||
@@ -325,12 +325,33 @@ export namespace Config {
|
||||
ref: "McpLocalConfig",
|
||||
})
|
||||
|
||||
export const McpOAuth = z
|
||||
.object({
|
||||
clientId: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("OAuth client ID. If not provided, dynamic client registration (RFC 7591) will be attempted."),
|
||||
clientSecret: z.string().optional().describe("OAuth client secret (if required by the authorization server)"),
|
||||
scope: z.string().optional().describe("OAuth scopes to request during authorization"),
|
||||
})
|
||||
.strict()
|
||||
.meta({
|
||||
ref: "McpOAuthConfig",
|
||||
})
|
||||
export type McpOAuth = z.infer<typeof McpOAuth>
|
||||
|
||||
export const McpRemote = z
|
||||
.object({
|
||||
type: z.literal("remote").describe("Type of MCP server connection"),
|
||||
url: z.string().describe("URL of the remote MCP server"),
|
||||
enabled: z.boolean().optional().describe("Enable or disable the MCP server on startup"),
|
||||
headers: z.record(z.string(), z.string()).optional().describe("Headers to send with the request"),
|
||||
oauth: z
|
||||
.union([McpOAuth, z.literal(false)])
|
||||
.optional()
|
||||
.describe(
|
||||
"OAuth authentication configuration for the MCP server. Set to false to disable OAuth auto-detection.",
|
||||
),
|
||||
timeout: z
|
||||
.number()
|
||||
.int()
|
||||
|
||||
2
packages/opencode/src/env/index.ts
vendored
@@ -2,7 +2,7 @@ import { Instance } from "../project/instance"
|
||||
|
||||
export namespace Env {
|
||||
const state = Instance.state(() => {
|
||||
return { ...process.env } as Record<string, string | undefined>
|
||||
return process.env as Record<string, string | undefined>
|
||||
})
|
||||
|
||||
export function get(key: string) {
|
||||
|
||||
@@ -9,6 +9,8 @@ import { createWrapper } from "@parcel/watcher/wrapper"
|
||||
import { lazy } from "@/util/lazy"
|
||||
import type ParcelWatcher from "@parcel/watcher"
|
||||
|
||||
declare const OPENCODE_LIBC: string | undefined
|
||||
|
||||
export namespace FileWatcher {
|
||||
const log = Log.create({ service: "file.watcher" })
|
||||
|
||||
@@ -24,7 +26,7 @@ export namespace FileWatcher {
|
||||
|
||||
const watcher = lazy(() => {
|
||||
const binding = require(
|
||||
`@parcel/watcher-${process.platform}-${process.arch}${process.platform === "linux" ? "-glibc" : ""}`,
|
||||
`@parcel/watcher-${process.platform}-${process.arch}${process.platform === "linux" ? `-${OPENCODE_LIBC || "glibc"}` : ""}`,
|
||||
)
|
||||
return createWrapper(binding) as typeof import("@parcel/watcher")
|
||||
})
|
||||
|
||||
@@ -255,3 +255,23 @@ export const dart: Info = {
|
||||
return Bun.which("dart") !== null
|
||||
},
|
||||
}
|
||||
|
||||
export const ocamlformat: Info = {
|
||||
name: "ocamlformat",
|
||||
command: ["ocamlformat", "-i", "$FILE"],
|
||||
extensions: [".ml", ".mli"],
|
||||
async enabled() {
|
||||
if (!Bun.which("ocamlformat")) return false
|
||||
const items = await Filesystem.findUp(".ocamlformat", Instance.directory, Instance.worktree)
|
||||
return items.length > 0
|
||||
},
|
||||
}
|
||||
|
||||
export const terraform: Info = {
|
||||
name: "terraform",
|
||||
command: ["terraform", "fmt", "$FILE"],
|
||||
extensions: [".tf", ".tfvars"],
|
||||
async enabled() {
|
||||
return Bun.which("terraform") !== null
|
||||
},
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ await Promise.all([
|
||||
fs.mkdir(Global.Path.bin, { recursive: true }),
|
||||
])
|
||||
|
||||
const CACHE_VERSION = "13"
|
||||
const CACHE_VERSION = "14"
|
||||
|
||||
const version = await Bun.file(path.join(Global.Path.cache, "version"))
|
||||
.text()
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Log } from "./util/log"
|
||||
import { AuthCommand } from "./cli/cmd/auth"
|
||||
import { AgentCommand } from "./cli/cmd/agent"
|
||||
import { UpgradeCommand } from "./cli/cmd/upgrade"
|
||||
import { UninstallCommand } from "./cli/cmd/uninstall"
|
||||
import { ModelsCommand } from "./cli/cmd/models"
|
||||
import { UI } from "./cli/ui"
|
||||
import { Installation } from "./installation"
|
||||
@@ -42,6 +43,7 @@ process.on("uncaughtException", (e) => {
|
||||
const cli = yargs(hideBin(process.argv))
|
||||
.parserConfiguration({ "populate--": true })
|
||||
.scriptName("opencode")
|
||||
.wrap(100)
|
||||
.help("help", "show help")
|
||||
.alias("help", "h")
|
||||
.version("version", "show version number", Installation.VERSION)
|
||||
@@ -86,6 +88,7 @@ const cli = yargs(hideBin(process.argv))
|
||||
.command(AuthCommand)
|
||||
.command(AgentCommand)
|
||||
.command(UpgradeCommand)
|
||||
.command(UninstallCommand)
|
||||
.command(ServeCommand)
|
||||
.command(WebCommand)
|
||||
.command(ModelsCommand)
|
||||
|
||||