Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7962f774ad | ||
|
|
7d00a49c2f | ||
|
|
c35c15a3ac | ||
|
|
11840191f8 | ||
|
|
9672a7b056 | ||
|
|
66a34798a4 |
5
.github/workflows/format.yml
vendored
@@ -18,8 +18,6 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
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
|
||||
@@ -29,4 +27,5 @@ jobs:
|
||||
./script/format.ts
|
||||
env:
|
||||
CI: true
|
||||
PUSH_BRANCH: ${{ github.event.pull_request.head.ref || github.ref_name }}
|
||||
GITHUB_HEAD_REF: ${{ github.head_ref }}
|
||||
GITHUB_REF_NAME: ${{ github.ref_name }}
|
||||
|
||||
2
.github/workflows/publish.yml
vendored
@@ -82,9 +82,7 @@ jobs:
|
||||
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
|
||||
|
||||
publish-tauri:
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
settings:
|
||||
- host: macos-latest
|
||||
|
||||
327
STATS.md
@@ -1,166 +1,165 @@
|
||||
# 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) |
|
||||
| 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) |
|
||||
| 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) |
|
||||
|
||||
58
bun.lock
@@ -20,7 +20,7 @@
|
||||
},
|
||||
"packages/console/app": {
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"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.137",
|
||||
"version": "1.0.134",
|
||||
"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.137",
|
||||
"version": "1.0.134",
|
||||
"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.137",
|
||||
"version": "1.0.134",
|
||||
"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.137",
|
||||
"version": "1.0.134",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
@@ -168,7 +168,7 @@
|
||||
},
|
||||
"packages/enterprise": {
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"dependencies": {
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
"@opencode-ai/util": "workspace:*",
|
||||
@@ -196,7 +196,7 @@
|
||||
},
|
||||
"packages/function": {
|
||||
"name": "@opencode-ai/function",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"dependencies": {
|
||||
"@octokit/auth-app": "8.0.1",
|
||||
"@octokit/rest": "22.0.0",
|
||||
@@ -212,7 +212,7 @@
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "opencode",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"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.59",
|
||||
"@opentui/solid": "0.1.59",
|
||||
"@opentui/core": "0.1.56",
|
||||
"@opentui/solid": "0.1.56",
|
||||
"@parcel/watcher": "2.5.1",
|
||||
"@pierre/precision-diffs": "catalog:",
|
||||
"@solid-primitives/event-bus": "1.1.2",
|
||||
@@ -285,9 +285,7 @@
|
||||
"@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:",
|
||||
@@ -304,7 +302,7 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"zod": "catalog:",
|
||||
@@ -324,7 +322,7 @@
|
||||
},
|
||||
"packages/sdk/js": {
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "0.88.1",
|
||||
"@tsconfig/node22": "catalog:",
|
||||
@@ -335,7 +333,7 @@
|
||||
},
|
||||
"packages/slack": {
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@slack/bolt": "^3.17.1",
|
||||
@@ -348,7 +346,7 @@
|
||||
},
|
||||
"packages/tauri": {
|
||||
"name": "@opencode-ai/tauri",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"dependencies": {
|
||||
"@opencode-ai/desktop": "workspace:*",
|
||||
"@tauri-apps/api": "^2",
|
||||
@@ -368,7 +366,7 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
@@ -400,7 +398,7 @@
|
||||
},
|
||||
"packages/util": {
|
||||
"name": "@opencode-ai/util",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"dependencies": {
|
||||
"zod": "catalog:",
|
||||
},
|
||||
@@ -411,7 +409,7 @@
|
||||
},
|
||||
"packages/web": {
|
||||
"name": "@opencode-ai/web",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "12.6.3",
|
||||
"@astrojs/markdown-remark": "6.3.1",
|
||||
@@ -460,7 +458,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.10",
|
||||
"@pierre/precision-diffs": "0.6.0-beta.3",
|
||||
"@solidjs/meta": "0.29.4",
|
||||
"@solidjs/router": "0.15.4",
|
||||
"@solidjs/start": "https://pkg.pr.new/@solidjs/start@dfb2020",
|
||||
@@ -1145,21 +1143,21 @@
|
||||
|
||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
||||
|
||||
"@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": ["@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-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.59", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JQWq7W/wkmTujW/2/Ig0d7S+701rul87LSW5txQ+GM4o6EWchqHrELwo6jcZpczsyOEj4fXxI2O8l4OVYyMa9A=="],
|
||||
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.56", "", { "os": "darwin", "cpu": "arm64" }, "sha512-x5U9J2k1Fmbb9Mdh1nOd/yZVpg4ARCrV5pFngpaeKrIWDhs8RLpQW3ap+r7uyFLGFkSn4h5wBR0jj6Dg+Tyw+A=="],
|
||||
|
||||
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.59", "", { "os": "darwin", "cpu": "x64" }, "sha512-GzafWzMP9Lt4AzUwQAk02lxgITgfvvo33OLCN265LtQBO8w23u0eB7Fjs9W+nmtcvzXtB9q6HuA0PvP9a3OioA=="],
|
||||
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.56", "", { "os": "darwin", "cpu": "x64" }, "sha512-7swq9rV/SaNVBWoUbC7mlP1VNyKBl7SSwmyVMkcaBP71lkm95zWuh4pgGj82fLgZ9gITRBD95TJVDmTovOyW0A=="],
|
||||
|
||||
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.59", "", { "os": "linux", "cpu": "arm64" }, "sha512-QMMFg3dr2v43g3jICgzNFYQyU4YL3zHw733MVJINC+c882+qiQ8l0utTFoVEx/iRYeBzFvMVrKZ4f6G8fFrtrw=="],
|
||||
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.56", "", { "os": "linux", "cpu": "arm64" }, "sha512-v8b+kiTlynAJzR0hFeVpGFzVi5PGqXAe3Zql9iTiQqTExkm/sR34sfC/P6rBOUhuAnos8ovPDKWtDb6eCTSm9g=="],
|
||||
|
||||
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.59", "", { "os": "linux", "cpu": "x64" }, "sha512-XSblVjhW/7+Xs+/o+xJHwHn74nw9j69mnPAFiNdH0d8ilP4j09nUYHZOvQ89sHZaMYeSIuJEciHnh/qP0n5QXQ=="],
|
||||
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.56", "", { "os": "linux", "cpu": "x64" }, "sha512-lbxgvAi5SBswK/2hoMPtLhPvJxASgquPUwvGTRHqzDkCvrOChP/loTjBQpL09/nAFc3jbM3SAbZtnEgA2SGYVw=="],
|
||||
|
||||
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.59", "", { "os": "win32", "cpu": "arm64" }, "sha512-GU5pPUcTpYmeOUYKpQgAPx0VKBMrfz5LNZlK8gm/jlo2CbLrIW7QLMWCoxncVZmNYqYJeG+KUZkmXYe5KLPXCQ=="],
|
||||
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.56", "", { "os": "win32", "cpu": "arm64" }, "sha512-RoCAbvDo+59OevX+6GrEGbaueERiBVnTaWJkrS41hRAD2fFS3CZpW7UuS5jIg7zn5clHmOGyfvCiBkTRXmgkhw=="],
|
||||
|
||||
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.59", "", { "os": "win32", "cpu": "x64" }, "sha512-InIawEI0TOG8MBBpavMq31WBRBjJ6XPuqFcsDnjqDJcXrRbNkguRW3PNXEwlyaU4tXHfYOsdlPpRtsysS8X/bQ=="],
|
||||
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.56", "", { "os": "win32", "cpu": "x64" }, "sha512-i6N5TjZU5gRkJsKmH8e/qY9vwSk0rh6A5t37mHDGlzN4E5yO/MbBrYH4ppLp5stps9Zfi1Re51ofJX1s2hZY/Q=="],
|
||||
|
||||
"@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=="],
|
||||
"@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=="],
|
||||
|
||||
"@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
|
||||
|
||||
@@ -1275,7 +1273,7 @@
|
||||
|
||||
"@petamoriken/float16": ["@petamoriken/float16@3.9.3", "", {}, "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g=="],
|
||||
|
||||
"@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=="],
|
||||
"@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=="],
|
||||
|
||||
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
||||
|
||||
@@ -2821,8 +2819,6 @@
|
||||
|
||||
"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=="],
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"nodeModules": "sha256-IzF5XDY09Z1p/8jgYIHhE/jpKPub15KKUpV+a/aKpuc="
|
||||
"nodeModules": "sha256-7ItLfqYrXzC6LO2iXZ8m+ZfQH1D7NWtcAcgRMO5NXZI="
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"@tsconfig/bun": "1.0.9",
|
||||
"@cloudflare/workers-types": "4.20251008.0",
|
||||
"@openauthjs/openauth": "0.0.0-20250322224806",
|
||||
"@pierre/precision-diffs": "0.6.0-beta.10",
|
||||
"@pierre/precision-diffs": "0.6.0-beta.3",
|
||||
"@tailwindcss/vite": "4.1.11",
|
||||
"diff": "8.0.2",
|
||||
"ai": "5.0.97",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"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.137",
|
||||
"version": "1.0.134",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-function",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-mail",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"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/entry.tsx" type="module"></script>
|
||||
<script src="/src/index.tsx" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "@opencode-ai/desktop",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
".": "./src/index.tsx",
|
||||
"./vite": "./vite.js"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
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>
|
||||
)
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
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
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import type { FileContent, FileNode, Model, Provider, File as FileStatus } from
|
||||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||
import { useSDK } from "./sdk"
|
||||
import { useSync } from "./sync"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { base64Encode } from "@/utils"
|
||||
|
||||
export type LocalFile = FileNode &
|
||||
Partial<{
|
||||
|
||||
@@ -7,7 +7,7 @@ import { TextSelection } from "./local"
|
||||
import { pipe, sumBy } from "remeda"
|
||||
import { AssistantMessage, UserMessage } from "@opencode-ai/sdk/v2"
|
||||
import { useParams } from "@solidjs/router"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { base64Encode } from "@/utils"
|
||||
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 : ""}.v2`,
|
||||
() => `${base64Encode(sync.data.project.worktree)}/session${params.id ? "/" + params.id : ""}.v1`,
|
||||
)
|
||||
|
||||
const [store, setStore] = makePersisted(
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
// @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!,
|
||||
)
|
||||
@@ -1,2 +0,0 @@
|
||||
export { PlatformProvider, type Platform } from "./PlatformContext"
|
||||
export { DesktopInterface } from "./DesktopInterface"
|
||||
73
packages/desktop/src/index.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
/* @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 "@opencode-ai/util/encode"
|
||||
import { base64Decode } from "@/utils"
|
||||
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 "@opencode-ai/util/encode"
|
||||
import { base64Encode } from "@/utils"
|
||||
import { For } from "solid-js"
|
||||
import { A } from "@solidjs/router"
|
||||
import { Button } from "@opencode-ai/ui/button"
|
||||
|
||||
@@ -3,9 +3,8 @@ 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 "@opencode-ai/util/encode"
|
||||
import { base64Decode, base64Encode } from "@/utils"
|
||||
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"
|
||||
@@ -66,7 +65,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-md"
|
||||
class="text-14-regular text-text-base max-w-3xs"
|
||||
variant="ghost"
|
||||
/>
|
||||
</div>
|
||||
@@ -117,14 +116,41 @@ export default function Layout(props: ParentProps) {
|
||||
style={{ width: layout.sidebar.opened() ? `${layout.sidebar.width()}px` : undefined }}
|
||||
>
|
||||
<Show when={layout.sidebar.opened()}>
|
||||
<ResizeHandle
|
||||
direction="horizontal"
|
||||
size={layout.sidebar.width()}
|
||||
min={150}
|
||||
max={window.innerWidth * 0.3}
|
||||
collapseThreshold={80}
|
||||
onResize={layout.sidebar.resize}
|
||||
onCollapse={layout.sidebar.close}
|
||||
<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)
|
||||
}}
|
||||
/>
|
||||
</Show>
|
||||
<div class="grow flex flex-col items-start self-stretch gap-4 p-2 min-h-0">
|
||||
|
||||
@@ -9,7 +9,6 @@ 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"
|
||||
@@ -31,8 +30,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()
|
||||
@@ -283,7 +282,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">
|
||||
<div class="relative bg-background-base size-full overflow-x-hidden flex flex-col items-start">
|
||||
<div class="min-h-0 grow w-full">
|
||||
<DragDropProvider
|
||||
onDragStart={handleDragStart}
|
||||
@@ -390,6 +389,7 @@ export default function Page() {
|
||||
? "pr-6 pl-18"
|
||||
: "px-6"),
|
||||
}}
|
||||
diffComponent={Diff}
|
||||
/>
|
||||
</div>
|
||||
</Match>
|
||||
@@ -438,6 +438,7 @@ export default function Page() {
|
||||
container: "px-6",
|
||||
}}
|
||||
diffs={session.diffs()}
|
||||
diffComponent={Diff}
|
||||
actions={
|
||||
<Tooltip value="Open in tab">
|
||||
<IconButton
|
||||
@@ -469,6 +470,7 @@ export default function Page() {
|
||||
container: "px-6",
|
||||
}}
|
||||
diffs={session.diffs()}
|
||||
diffComponent={Diff}
|
||||
split
|
||||
/>
|
||||
</div>
|
||||
@@ -491,11 +493,7 @@ export default function Page() {
|
||||
<Match when={file()}>
|
||||
{(f) => (
|
||||
<Code
|
||||
file={{
|
||||
name: f().path,
|
||||
contents: f().content?.content ?? "",
|
||||
cacheKey: checksum(f().content?.content ?? ""),
|
||||
}}
|
||||
file={{ name: f().path, contents: f().content?.content ?? "" }}
|
||||
overflow="scroll"
|
||||
class="pb-40"
|
||||
/>
|
||||
@@ -608,14 +606,41 @@ 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` }}
|
||||
>
|
||||
<ResizeHandle
|
||||
direction="vertical"
|
||||
size={layout.terminal.height()}
|
||||
min={100}
|
||||
max={window.innerHeight * 0.6}
|
||||
collapseThreshold={50}
|
||||
onResize={layout.terminal.resize}
|
||||
onCollapse={layout.terminal.close}
|
||||
<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)
|
||||
}}
|
||||
/>
|
||||
<Tabs variant="alt" value={session.terminal.active()} onChange={session.terminal.open}>
|
||||
<Tabs.List class="h-10">
|
||||
|
||||
7
packages/desktop/src/utils/encode.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
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 +1,2 @@
|
||||
export * from "./dom"
|
||||
export * from "./encode"
|
||||
|
||||
@@ -8,20 +8,53 @@
|
||||
"dark": "#15803D"
|
||||
},
|
||||
"favicon": "/favicon.svg",
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://opencode.ai/openapi.json"
|
||||
}
|
||||
],
|
||||
"navigation": {
|
||||
"tabs": [
|
||||
{
|
||||
"tab": "SDK",
|
||||
"tab": "Guides",
|
||||
"groups": [
|
||||
{
|
||||
"group": "Getting started",
|
||||
"pages": ["index", "quickstart", "development"],
|
||||
"openapi": "https://opencode.ai/openapi.json"
|
||||
"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"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tab": "API Reference",
|
||||
"openapi": "https://opencode.ai/openapi.json"
|
||||
}
|
||||
],
|
||||
"global": {}
|
||||
"global": {
|
||||
"anchors": [
|
||||
{
|
||||
"anchor": "Documentation",
|
||||
"href": "https://mintlify.com/docs",
|
||||
"icon": "book-open-cover"
|
||||
},
|
||||
{
|
||||
"anchor": "Blog",
|
||||
"href": "https://mintlify.com/blog",
|
||||
"icon": "newspaper"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"logo": {
|
||||
"light": "/logo/light.svg",
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../sdk/openapi.json
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -2,7 +2,6 @@ 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"
|
||||
@@ -19,7 +18,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 as SSRDiff } from "@opencode-ai/ui/diff-ssr"
|
||||
import { Diff } from "@opencode-ai/ui/diff-ssr"
|
||||
import { clientOnly } from "@solidjs/start"
|
||||
|
||||
const ClientOnlyDiff = clientOnly(() => import("@opencode-ai/ui/diff").then((m) => ({ default: m.Diff })))
|
||||
@@ -158,240 +157,234 @@ export default function () {
|
||||
const info = createMemo(() => data().session[match().index])
|
||||
|
||||
return (
|
||||
<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)
|
||||
}
|
||||
<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>
|
||||
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="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 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="px-4 flex items-center justify-center pt-20 pb-8 shrink-0">
|
||||
<Logo class="w-58.5 opacity-12" />
|
||||
<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 wide = createMemo(() => diffs().length === 0)
|
||||
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}
|
||||
/>
|
||||
)}
|
||||
</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>
|
||||
)
|
||||
|
||||
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">
|
||||
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={{ "hidden w-full flex-1 min-h-0": true, "md:flex": wide(), "lg:flex": !wide() }}>
|
||||
<div
|
||||
classList={{ "hidden w-full flex-1 min-h-0": true, "md:flex": wide(), "lg:flex": !wide() }}
|
||||
classList={{
|
||||
"@container relative shrink-0 pt-14 flex flex-col gap-10 min-h-0 w-full": true,
|
||||
"mx-auto max-w-146": !wide(),
|
||||
}}
|
||||
>
|
||||
<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(),
|
||||
"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,
|
||||
}}
|
||||
>
|
||||
<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,
|
||||
}}
|
||||
>
|
||||
{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>
|
||||
{title()}
|
||||
</div>
|
||||
<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">
|
||||
<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"),
|
||||
}}
|
||||
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>
|
||||
</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">
|
||||
<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()}
|
||||
classes={{
|
||||
root: "pb-20",
|
||||
header: "px-6",
|
||||
container: "px-6",
|
||||
header: "px-4",
|
||||
container: "px-4",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</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>
|
||||
</Tabs.Content>
|
||||
</Tabs>
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<div classList={{ "!overflow-hidden": true, "md:hidden": wide(), "lg:hidden": !wide() }}>
|
||||
{turns()}
|
||||
</div>
|
||||
</Match>
|
||||
</Switch>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</DataProvider>
|
||||
</DiffComponentProvider>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</DataProvider>
|
||||
)
|
||||
}}
|
||||
</Show>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
id = "opencode"
|
||||
name = "OpenCode"
|
||||
description = "The open source coding agent."
|
||||
version = "1.0.137"
|
||||
description = "The AI coding agent built for the terminal"
|
||||
version = "1.0.134"
|
||||
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.137/opencode-darwin-arm64.zip"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.134/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.137/opencode-darwin-x64.zip"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.134/opencode-darwin-x64.zip"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.linux-aarch64]
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.137/opencode-linux-arm64.tar.gz"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.134/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.137/opencode-linux-x64.tar.gz"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.134/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.137/opencode-windows-x64.zip"
|
||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.134/opencode-windows-x64.zip"
|
||||
cmd = "./opencode.exe"
|
||||
args = ["acp"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/function",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
BIN
packages/identity/avatar-dark.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
packages/identity/avatar-light.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
12
packages/identity/logo-dark.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 981 B |
12
packages/identity/logo-light.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 981 B |
18
packages/identity/logo-ornate-dark.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
18
packages/identity/logo-ornate-light.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
4
packages/identity/logo-square-dark.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 306 B |
4
packages/identity/logo-square-light.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 306 B |
4
packages/identity/logomark-dark.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 267 B |
4
packages/identity/logomark-light.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 267 B |
|
Before Width: | Height: | Size: 144 B |
|
Before Width: | Height: | Size: 330 B |
|
Before Width: | Height: | Size: 330 B |
|
Before Width: | Height: | Size: 122 B |
@@ -1,5 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 325 B |
@@ -1,7 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 612 B |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"name": "opencode",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
@@ -23,9 +23,7 @@
|
||||
"@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:",
|
||||
@@ -66,8 +64,8 @@
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@opencode-ai/util": "workspace:*",
|
||||
"@openrouter/ai-sdk-provider": "1.2.8",
|
||||
"@opentui/core": "0.1.59",
|
||||
"@opentui/solid": "0.1.59",
|
||||
"@opentui/core": "0.1.56",
|
||||
"@opentui/solid": "0.1.56",
|
||||
"@parcel/watcher": "2.5.1",
|
||||
"@pierre/precision-diffs": "catalog:",
|
||||
"@solid-primitives/event-bus": "1.1.2",
|
||||
|
||||
@@ -128,7 +128,6 @@ 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,8 +199,6 @@ 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"`,
|
||||
|
||||
@@ -35,22 +35,16 @@ export namespace Auth {
|
||||
const filepath = path.join(Global.Path.data, "auth.json")
|
||||
|
||||
export async function get(providerID: string) {
|
||||
const auth = await all()
|
||||
return auth[providerID]
|
||||
const file = Bun.file(filepath)
|
||||
return file
|
||||
.json()
|
||||
.catch(() => ({}))
|
||||
.then((x) => x[providerID] as Info | undefined)
|
||||
}
|
||||
|
||||
export async function all(): Promise<Record<string, Info>> {
|
||||
const file = Bun.file(filepath)
|
||||
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>,
|
||||
)
|
||||
return file.json().catch(() => ({}))
|
||||
}
|
||||
|
||||
export async function set(key: string, info: Info) {
|
||||
|
||||
@@ -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 = Object.entries(await Auth.all())
|
||||
const results = await Auth.all().then((x) => Object.entries(x))
|
||||
const database = await ModelsDev.get()
|
||||
|
||||
for (const [providerID, result] of results) {
|
||||
@@ -143,10 +143,7 @@ export const AuthLoginCommand = cmd({
|
||||
map((x) => ({
|
||||
label: x.name,
|
||||
value: x.id,
|
||||
hint: {
|
||||
opencode: "recommended",
|
||||
anthropic: "Claude Max or API key",
|
||||
}[x.id],
|
||||
hint: priority[x.id] <= 1 ? "recommended" : undefined,
|
||||
})),
|
||||
),
|
||||
{
|
||||
|
||||
@@ -5,26 +5,6 @@ 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
|
||||
|
||||
@@ -12,7 +12,6 @@ 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"
|
||||
@@ -302,14 +301,6 @@ function App() {
|
||||
dialog.replace(() => <DialogAgent />)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Toggle MCPs",
|
||||
value: "mcp.list",
|
||||
category: "Agent",
|
||||
onSelect: () => {
|
||||
dialog.replace(() => <DialogMcp />)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Agent cycle",
|
||||
value: "agent.cycle",
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
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
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -26,7 +26,6 @@ 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()
|
||||
|
||||
@@ -5,12 +5,10 @@ import { onCleanup, onMount } from "solid-js"
|
||||
|
||||
export function DialogThemeList() {
|
||||
const theme = useTheme()
|
||||
const options = Object.keys(theme.all())
|
||||
.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" }))
|
||||
.map((value) => ({
|
||||
title: value,
|
||||
value: value,
|
||||
}))
|
||||
const options = Object.keys(theme.all()).map((value) => ({
|
||||
title: value,
|
||||
value: value,
|
||||
}))
|
||||
const dialog = useDialog()
|
||||
let confirmed = false
|
||||
let ref: DialogSelectRef<string>
|
||||
|
||||
@@ -307,14 +307,10 @@ 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",
|
||||
@@ -497,7 +493,7 @@ export function Autocomplete(props: {
|
||||
each={options()}
|
||||
fallback={
|
||||
<box paddingLeft={1} paddingRight={1}>
|
||||
<text fg={theme.textMuted}>No matching items</text>
|
||||
<text>No matching items</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -10,14 +10,12 @@ 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 }) {
|
||||
@@ -312,27 +310,9 @@ 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
|
||||
},
|
||||
|
||||
@@ -6,7 +6,6 @@ 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" }
|
||||
@@ -22,7 +21,6 @@ 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" }
|
||||
@@ -94,7 +92,6 @@ type ThemeColors = {
|
||||
|
||||
type Theme = ThemeColors & {
|
||||
_hasSelectedListItemText: boolean
|
||||
thinkingOpacity: number
|
||||
}
|
||||
|
||||
export function selectedForeground(theme: Theme): RGBA {
|
||||
@@ -127,7 +124,6 @@ type ThemeJson = {
|
||||
theme: Omit<Record<keyof ThemeColors, ColorValue>, "selectedListItemText" | "backgroundMenu"> & {
|
||||
selectedListItemText?: ColorValue
|
||||
backgroundMenu?: ColorValue
|
||||
thinkingOpacity?: number
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +131,6 @@ export const DEFAULT_THEMES: Record<string, ThemeJson> = {
|
||||
aura,
|
||||
ayu,
|
||||
catppuccin,
|
||||
["catppuccin-macchiato"]: catppuccinMacchiato,
|
||||
cobalt2,
|
||||
dracula,
|
||||
everforest,
|
||||
@@ -151,7 +146,6 @@ export const DEFAULT_THEMES: Record<string, ThemeJson> = {
|
||||
nord,
|
||||
["one-dark"]: onedark,
|
||||
opencode,
|
||||
orng,
|
||||
palenight,
|
||||
rosepine,
|
||||
solarized,
|
||||
@@ -187,9 +181,9 @@ function resolveTheme(theme: ThemeJson, mode: "dark" | "light") {
|
||||
|
||||
const resolved = Object.fromEntries(
|
||||
Object.entries(theme.theme)
|
||||
.filter(([key]) => key !== "selectedListItemText" && key !== "backgroundMenu" && key !== "thinkingOpacity")
|
||||
.filter(([key]) => key !== "selectedListItemText" && key !== "backgroundMenu")
|
||||
.map(([key, value]) => {
|
||||
return [key, resolveColor(value as ColorValue)]
|
||||
return [key, resolveColor(value)]
|
||||
}),
|
||||
) as Partial<ThemeColors>
|
||||
|
||||
@@ -210,13 +204,9 @@ 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
|
||||
}
|
||||
|
||||
@@ -562,7 +552,7 @@ function generateSubtleSyntax(theme: Theme) {
|
||||
Math.round(fg.r * 255),
|
||||
Math.round(fg.g * 255),
|
||||
Math.round(fg.b * 255),
|
||||
Math.round(theme.thinkingOpacity * 255),
|
||||
Math.round(0.6 * 255),
|
||||
),
|
||||
},
|
||||
}
|
||||
@@ -574,12 +564,6 @@ function generateSubtleSyntax(theme: Theme) {
|
||||
|
||||
function getSyntaxRules(theme: Theme) {
|
||||
return [
|
||||
{
|
||||
scope: ["default"],
|
||||
style: {
|
||||
foreground: theme.text,
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: ["prompt"],
|
||||
style: {
|
||||
|
||||
@@ -1,233 +0,0 @@
|
||||
{
|
||||
"$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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,245 +0,0 @@
|
||||
{
|
||||
"$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,12 +24,8 @@ 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={connectedMcpCount() > 0}>
|
||||
<Show when={Object.keys(sync.data.mcp).length > 0}>
|
||||
<box flexShrink={0} flexDirection="row" gap={1}>
|
||||
<text fg={theme.text}>
|
||||
<Switch>
|
||||
@@ -39,7 +35,7 @@ export function Home() {
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<span style={{ fg: theme.success }}>•</span>{" "}
|
||||
{Locale.pluralize(connectedMcpCount(), "{} mcp server", "{} mcp servers")}
|
||||
{Locale.pluralize(Object.values(sync.data.mcp).length, "{} mcp server", "{} mcp servers")}
|
||||
</Match>
|
||||
</Switch>
|
||||
</text>
|
||||
@@ -89,7 +85,7 @@ export function Home() {
|
||||
<span style={{ fg: theme.success }}>⊙ </span>
|
||||
</Match>
|
||||
</Switch>
|
||||
{connectedMcpCount()} MCP
|
||||
{Object.keys(sync.data.mcp).length} MCP
|
||||
</text>
|
||||
<text fg={theme.textMuted}>/status</text>
|
||||
</Show>
|
||||
|
||||
@@ -4,19 +4,13 @@ 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()
|
||||
|
||||
@@ -57,12 +51,6 @@ 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>
|
||||
|
||||
@@ -1049,12 +1049,12 @@ function UserMessage(props: {
|
||||
<Show
|
||||
when={queued()}
|
||||
fallback={
|
||||
<Show when={ctx.showTimestamps()}>
|
||||
<span style={{ fg: theme.textMuted }}>
|
||||
{ctx.usernameVisible() ? " · " : " "}
|
||||
{Locale.todayTimeOrDateTime(props.message.time.created)}
|
||||
</span>
|
||||
</Show>
|
||||
<span style={{ fg: theme.textMuted }}>
|
||||
{ctx.usernameVisible() ? " · " : " "}
|
||||
{ctx.showTimestamps()
|
||||
? Locale.todayTimeOrDateTime(props.message.time.created)
|
||||
: Locale.time(props.message.time.created)}
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<span style={{ bg: theme.accent, fg: theme.backgroundPanel, bold: true }}> QUEUED </span>
|
||||
@@ -1600,7 +1600,6 @@ ToolRegistry.register<typeof EditTool>({
|
||||
showLineNumbers={true}
|
||||
width="100%"
|
||||
wrapMode={ctx.diffWrapMode()}
|
||||
fg={theme.text}
|
||||
addedBg={theme.diffAddedBg}
|
||||
removedBg={theme.diffRemovedBg}
|
||||
contextBg={theme.diffContextBg}
|
||||
|
||||
@@ -248,7 +248,7 @@ export function Sidebar(props: { sessionID: string }) {
|
||||
</box>
|
||||
</scrollbox>
|
||||
|
||||
<box flexShrink={0} gap={1} paddingTop={1}>
|
||||
<box flexShrink={0} gap={1}>
|
||||
<Show when={!hasProviders()}>
|
||||
<box
|
||||
backgroundColor={theme.backgroundElement}
|
||||
@@ -275,7 +275,7 @@ export function Sidebar(props: { sessionID: string }) {
|
||||
</box>
|
||||
</box>
|
||||
</Show>
|
||||
<text fg={theme.text}>{directory()}</text>
|
||||
<text fg={theme.textMuted}>{directory()}</text>
|
||||
<text fg={theme.textMuted}>
|
||||
<span style={{ fg: theme.success }}>•</span> <b>Open</b>
|
||||
<span style={{ fg: theme.text }}>
|
||||
|
||||
@@ -60,6 +60,7 @@ 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,9 +49,6 @@ 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">
|
||||
|
||||
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,8 +9,6 @@ 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" })
|
||||
|
||||
@@ -26,7 +24,7 @@ export namespace FileWatcher {
|
||||
|
||||
const watcher = lazy(() => {
|
||||
const binding = require(
|
||||
`@parcel/watcher-${process.platform}-${process.arch}${process.platform === "linux" ? `-${OPENCODE_LIBC || "glibc"}` : ""}`,
|
||||
`@parcel/watcher-${process.platform}-${process.arch}${process.platform === "linux" ? "-glibc" : ""}`,
|
||||
)
|
||||
return createWrapper(binding) as typeof import("@parcel/watcher")
|
||||
})
|
||||
|
||||
@@ -255,23 +255,3 @@ 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 = "14"
|
||||
const CACHE_VERSION = "13"
|
||||
|
||||
const version = await Bun.file(path.join(Global.Path.cache, "version"))
|
||||
.text()
|
||||
|
||||
@@ -43,7 +43,6 @@ 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)
|
||||
|
||||
@@ -103,9 +103,4 @@ export const LANGUAGE_EXTENSIONS: Record<string, string> = {
|
||||
".zig": "zig",
|
||||
".zon": "zig",
|
||||
".astro": "astro",
|
||||
".ml": "ocaml",
|
||||
".mli": "ocaml",
|
||||
".tf": "terraform",
|
||||
".tfvars": "terraform-vars",
|
||||
".hcl": "hcl",
|
||||
} as const
|
||||
|
||||
@@ -1184,144 +1184,4 @@ export namespace LSPServer {
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const Ocaml: Info = {
|
||||
id: "ocaml-lsp",
|
||||
extensions: [".ml", ".mli"],
|
||||
root: NearestRoot(["dune-project", "dune-workspace", ".merlin", "opam"]),
|
||||
async spawn(root) {
|
||||
const bin = Bun.which("ocamllsp")
|
||||
if (!bin) {
|
||||
log.info("ocamllsp not found, please install ocaml-lsp-server")
|
||||
return
|
||||
}
|
||||
return {
|
||||
process: spawn(bin, {
|
||||
cwd: root,
|
||||
}),
|
||||
}
|
||||
},
|
||||
}
|
||||
export const BashLS: Info = {
|
||||
id: "bash",
|
||||
extensions: [".sh", ".bash", ".zsh", ".ksh"],
|
||||
root: async () => Instance.directory,
|
||||
async spawn(root) {
|
||||
let binary = Bun.which("bash-language-server")
|
||||
const args: string[] = []
|
||||
if (!binary) {
|
||||
const js = path.join(Global.Path.bin, "node_modules", "bash-language-server", "out", "cli.js")
|
||||
if (!(await Bun.file(js).exists())) {
|
||||
if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return
|
||||
await Bun.spawn([BunProc.which(), "install", "bash-language-server"], {
|
||||
cwd: Global.Path.bin,
|
||||
env: {
|
||||
...process.env,
|
||||
BUN_BE_BUN: "1",
|
||||
},
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
stdin: "pipe",
|
||||
}).exited
|
||||
}
|
||||
binary = BunProc.which()
|
||||
args.push("run", js)
|
||||
}
|
||||
args.push("start")
|
||||
const proc = spawn(binary, args, {
|
||||
cwd: root,
|
||||
env: {
|
||||
...process.env,
|
||||
BUN_BE_BUN: "1",
|
||||
},
|
||||
})
|
||||
return {
|
||||
process: proc,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const TerraformLS: Info = {
|
||||
id: "terraform",
|
||||
extensions: [".tf", ".tfvars"],
|
||||
root: NearestRoot([".terraform.lock.hcl", "terraform.tfstate", "*.tf"]),
|
||||
async spawn(root) {
|
||||
let bin = Bun.which("terraform-ls", {
|
||||
PATH: process.env["PATH"] + ":" + Global.Path.bin,
|
||||
})
|
||||
|
||||
if (!bin) {
|
||||
if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return
|
||||
log.info("downloading terraform-ls from GitHub releases")
|
||||
|
||||
const releaseResponse = await fetch("https://api.github.com/repos/hashicorp/terraform-ls/releases/latest")
|
||||
if (!releaseResponse.ok) {
|
||||
log.error("Failed to fetch terraform-ls release info")
|
||||
return
|
||||
}
|
||||
|
||||
const release = (await releaseResponse.json()) as {
|
||||
tag_name?: string
|
||||
assets?: { name?: string; browser_download_url?: string }[]
|
||||
}
|
||||
const version = release.tag_name?.replace("v", "")
|
||||
if (!version) {
|
||||
log.error("terraform-ls release did not include a version tag")
|
||||
return
|
||||
}
|
||||
|
||||
const platform = process.platform
|
||||
const arch = process.arch
|
||||
|
||||
const tfArch = arch === "arm64" ? "arm64" : "amd64"
|
||||
const tfPlatform = platform === "win32" ? "windows" : platform
|
||||
|
||||
const assetName = `terraform-ls_${version}_${tfPlatform}_${tfArch}.zip`
|
||||
|
||||
const assets = release.assets ?? []
|
||||
const asset = assets.find((a) => a.name === assetName)
|
||||
if (!asset?.browser_download_url) {
|
||||
log.error(`Could not find asset ${assetName} in terraform-ls release`)
|
||||
return
|
||||
}
|
||||
|
||||
const downloadResponse = await fetch(asset.browser_download_url)
|
||||
if (!downloadResponse.ok) {
|
||||
log.error("Failed to download terraform-ls")
|
||||
return
|
||||
}
|
||||
|
||||
const tempPath = path.join(Global.Path.bin, assetName)
|
||||
await Bun.file(tempPath).write(downloadResponse)
|
||||
|
||||
await $`unzip -o -q ${tempPath}`.cwd(Global.Path.bin).nothrow()
|
||||
await fs.rm(tempPath, { force: true })
|
||||
|
||||
bin = path.join(Global.Path.bin, "terraform-ls" + (platform === "win32" ? ".exe" : ""))
|
||||
|
||||
if (!(await Bun.file(bin).exists())) {
|
||||
log.error("Failed to extract terraform-ls binary")
|
||||
return
|
||||
}
|
||||
|
||||
if (platform !== "win32") {
|
||||
await $`chmod +x ${bin}`.nothrow()
|
||||
}
|
||||
|
||||
log.info(`installed terraform-ls`, { bin })
|
||||
}
|
||||
|
||||
return {
|
||||
process: spawn(bin, ["serve"], {
|
||||
cwd: root,
|
||||
}),
|
||||
initialization: {
|
||||
experimentalFeatures: {
|
||||
prefillRequiredFields: true,
|
||||
validateOnSave: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,12 +86,6 @@ export namespace MCP {
|
||||
|
||||
await Promise.all(
|
||||
Object.entries(config).map(async ([key, mcp]) => {
|
||||
// If disabled by config, mark as disabled without trying to connect
|
||||
if (mcp.enabled === false) {
|
||||
status[key] = { status: "disabled" }
|
||||
return
|
||||
}
|
||||
|
||||
const result = await create(key, mcp).catch(() => undefined)
|
||||
if (!result) return
|
||||
|
||||
@@ -325,73 +319,18 @@ export namespace MCP {
|
||||
}
|
||||
|
||||
export async function status() {
|
||||
const s = await state()
|
||||
const cfg = await Config.get()
|
||||
const config = cfg.mcp ?? {}
|
||||
const result: Record<string, Status> = {}
|
||||
|
||||
// Include all MCPs from config, not just connected ones
|
||||
for (const key of Object.keys(config)) {
|
||||
result[key] = s.status[key] ?? { status: "disabled" }
|
||||
}
|
||||
|
||||
return result
|
||||
return state().then((state) => state.status)
|
||||
}
|
||||
|
||||
export async function clients() {
|
||||
return state().then((state) => state.clients)
|
||||
}
|
||||
|
||||
export async function connect(name: string) {
|
||||
const cfg = await Config.get()
|
||||
const config = cfg.mcp ?? {}
|
||||
const mcp = config[name]
|
||||
if (!mcp) {
|
||||
log.error("MCP config not found", { name })
|
||||
return
|
||||
}
|
||||
|
||||
const result = await create(name, { ...mcp, enabled: true })
|
||||
|
||||
if (!result) {
|
||||
const s = await state()
|
||||
s.status[name] = {
|
||||
status: "failed",
|
||||
error: "Unknown error during connection",
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const s = await state()
|
||||
s.status[name] = result.status
|
||||
if (result.mcpClient) {
|
||||
s.clients[name] = result.mcpClient
|
||||
}
|
||||
}
|
||||
|
||||
export async function disconnect(name: string) {
|
||||
const s = await state()
|
||||
const client = s.clients[name]
|
||||
if (client) {
|
||||
await client.close().catch((error) => {
|
||||
log.error("Failed to close MCP client", { name, error })
|
||||
})
|
||||
delete s.clients[name]
|
||||
}
|
||||
s.status[name] = { status: "disabled" }
|
||||
}
|
||||
|
||||
export async function tools() {
|
||||
const result: Record<string, Tool> = {}
|
||||
const s = await state()
|
||||
const clientsSnapshot = await clients()
|
||||
|
||||
for (const [clientName, client] of Object.entries(clientsSnapshot)) {
|
||||
// Only include tools from connected MCPs (skip disabled ones)
|
||||
if (s.status[clientName]?.status !== "connected") {
|
||||
continue
|
||||
}
|
||||
|
||||
const tools = await client.tools().catch((e) => {
|
||||
log.error("failed to get tools", { clientName, error: e.message })
|
||||
const failedStatus = {
|
||||
|
||||
@@ -28,8 +28,8 @@ export namespace Plugin {
|
||||
}
|
||||
const plugins = [...(config.plugin ?? [])]
|
||||
if (!Flag.OPENCODE_DISABLE_DEFAULT_PLUGINS) {
|
||||
plugins.push("opencode-copilot-auth@0.0.9")
|
||||
plugins.push("opencode-anthropic-auth@0.0.5")
|
||||
plugins.push("opencode-copilot-auth@0.0.8")
|
||||
plugins.push("opencode-anthropic-auth@0.0.4")
|
||||
}
|
||||
for (let plugin of plugins) {
|
||||
log.info("loading plugin", { path: plugin })
|
||||
|
||||
@@ -287,21 +287,13 @@ export namespace Provider {
|
||||
},
|
||||
"sap-ai-core": async () => {
|
||||
const auth = await Auth.get("sap-ai-core")
|
||||
const envServiceKey = iife(() => {
|
||||
const envAICoreServiceKey = Env.get("AICORE_SERVICE_KEY")
|
||||
if (envAICoreServiceKey) return envAICoreServiceKey
|
||||
if (auth?.type === "api") {
|
||||
Env.set("AICORE_SERVICE_KEY", auth.key)
|
||||
return auth.key
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
const deploymentId = Env.get("AICORE_DEPLOYMENT_ID")
|
||||
const resourceGroup = Env.get("AICORE_RESOURCE_GROUP")
|
||||
const serviceKey = Env.get("SAP_AI_SERVICE_KEY") || (auth?.type === "api" ? auth.key : undefined)
|
||||
const deploymentId = Env.get("SAP_AI_DEPLOYMENT_ID") || "d65d81e7c077e583"
|
||||
const resourceGroup = Env.get("SAP_AI_RESOURCE_GROUP") || "default"
|
||||
|
||||
return {
|
||||
autoload: !!envServiceKey,
|
||||
options: envServiceKey ? { deploymentId, resourceGroup } : {},
|
||||
autoload: !!serviceKey,
|
||||
options: serviceKey ? { serviceKey, deploymentId, resourceGroup } : {},
|
||||
async getModel(sdk: any, modelID: string) {
|
||||
return sdk(modelID)
|
||||
},
|
||||
@@ -803,7 +795,7 @@ export namespace Provider {
|
||||
const mod = await import(installedPath)
|
||||
|
||||
const fn = mod[Object.keys(mod).find((key) => key.startsWith("create"))!]
|
||||
const loaded = fn({
|
||||
const loaded = await fn({
|
||||
name: model.providerID,
|
||||
...options,
|
||||
})
|
||||
|
||||
@@ -2,17 +2,6 @@ import type { APICallError, ModelMessage } from "ai"
|
||||
import { unique } from "remeda"
|
||||
import type { JSONSchema } from "zod/v4/core"
|
||||
import type { Provider } from "./provider"
|
||||
import type { ModelsDev } from "./models"
|
||||
|
||||
type Modality = NonNullable<ModelsDev.Model["modalities"]>["input"][number]
|
||||
|
||||
function mimeToModality(mime: string): Modality | undefined {
|
||||
if (mime.startsWith("image/")) return "image"
|
||||
if (mime.startsWith("audio/")) return "audio"
|
||||
if (mime.startsWith("video/")) return "video"
|
||||
if (mime === "application/pdf") return "pdf"
|
||||
return undefined
|
||||
}
|
||||
|
||||
export namespace ProviderTransform {
|
||||
function normalizeMessages(msgs: ModelMessage[], model: Provider.Model): ModelMessage[] {
|
||||
@@ -159,32 +148,7 @@ export namespace ProviderTransform {
|
||||
return msgs
|
||||
}
|
||||
|
||||
function unsupportedParts(msgs: ModelMessage[], model: Provider.Model): ModelMessage[] {
|
||||
return msgs.map((msg) => {
|
||||
if (msg.role !== "user" || !Array.isArray(msg.content)) return msg
|
||||
|
||||
const filtered = msg.content.map((part) => {
|
||||
if (part.type !== "file" && part.type !== "image") return part
|
||||
|
||||
const mime = part.type === "image" ? part.image.toString().split(";")[0].replace("data:", "") : part.mediaType
|
||||
const filename = part.type === "file" ? part.filename : undefined
|
||||
const modality = mimeToModality(mime)
|
||||
if (!modality) return part
|
||||
if (model.capabilities.input[modality]) return part
|
||||
|
||||
const name = filename ? `"${filename}"` : modality
|
||||
return {
|
||||
type: "text" as const,
|
||||
text: `ERROR: Cannot read ${name} (this model does not support ${modality} input). Inform the user.`,
|
||||
}
|
||||
})
|
||||
|
||||
return { ...msg, content: filtered }
|
||||
})
|
||||
}
|
||||
|
||||
export function message(msgs: ModelMessage[], model: Provider.Model) {
|
||||
msgs = unsupportedParts(msgs, model)
|
||||
msgs = normalizeMessages(msgs, model)
|
||||
if (model.providerID === "anthropic" || model.api.id.includes("anthropic") || model.api.id.includes("claude")) {
|
||||
msgs = applyCaching(msgs, model.providerID)
|
||||
|
||||
@@ -8,8 +8,7 @@ export const ProjectRoute = new Hono()
|
||||
.get(
|
||||
"/",
|
||||
describeRoute({
|
||||
summary: "List all projects",
|
||||
description: "Get a list of projects that have been opened with OpenCode.",
|
||||
description: "List all projects",
|
||||
operationId: "project.list",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -30,12 +29,11 @@ export const ProjectRoute = new Hono()
|
||||
.get(
|
||||
"/current",
|
||||
describeRoute({
|
||||
summary: "Get current project",
|
||||
description: "Retrieve the currently active project that OpenCode is working with.",
|
||||
description: "Get the current project",
|
||||
operationId: "project.current",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Current project information",
|
||||
description: "Current project",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(Project.Info),
|
||||
|
||||
@@ -97,8 +97,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/global/event",
|
||||
describeRoute({
|
||||
summary: "Get global events",
|
||||
description: "Subscribe to global events from the OpenCode system using server-sent events.",
|
||||
description: "Get events",
|
||||
operationId: "global.event",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -169,8 +168,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/pty",
|
||||
describeRoute({
|
||||
summary: "List PTY sessions",
|
||||
description: "Get a list of all active pseudo-terminal (PTY) sessions managed by OpenCode.",
|
||||
description: "List all PTY sessions",
|
||||
operationId: "pty.list",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -190,8 +188,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/pty",
|
||||
describeRoute({
|
||||
summary: "Create PTY session",
|
||||
description: "Create a new pseudo-terminal (PTY) session for running shell commands and processes.",
|
||||
description: "Create a new PTY session",
|
||||
operationId: "pty.create",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -214,8 +211,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/pty/:ptyID",
|
||||
describeRoute({
|
||||
summary: "Get PTY session",
|
||||
description: "Retrieve detailed information about a specific pseudo-terminal (PTY) session.",
|
||||
description: "Get PTY session info",
|
||||
operationId: "pty.get",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -241,8 +237,7 @@ export namespace Server {
|
||||
.put(
|
||||
"/pty/:ptyID",
|
||||
describeRoute({
|
||||
summary: "Update PTY session",
|
||||
description: "Update properties of an existing pseudo-terminal (PTY) session.",
|
||||
description: "Update PTY session",
|
||||
operationId: "pty.update",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -266,8 +261,7 @@ export namespace Server {
|
||||
.delete(
|
||||
"/pty/:ptyID",
|
||||
describeRoute({
|
||||
summary: "Remove PTY session",
|
||||
description: "Remove and terminate a specific pseudo-terminal (PTY) session.",
|
||||
description: "Remove a PTY session",
|
||||
operationId: "pty.remove",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -290,9 +284,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/pty/:ptyID/connect",
|
||||
describeRoute({
|
||||
summary: "Connect to PTY session",
|
||||
description:
|
||||
"Establish a WebSocket connection to interact with a pseudo-terminal (PTY) session in real-time.",
|
||||
description: "Connect to a PTY session",
|
||||
operationId: "pty.connect",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -328,8 +320,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/config",
|
||||
describeRoute({
|
||||
summary: "Get configuration",
|
||||
description: "Retrieve the current OpenCode configuration settings and preferences.",
|
||||
description: "Get config info",
|
||||
operationId: "config.get",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -350,8 +341,7 @@ export namespace Server {
|
||||
.patch(
|
||||
"/config",
|
||||
describeRoute({
|
||||
summary: "Update configuration",
|
||||
description: "Update OpenCode configuration settings and preferences.",
|
||||
description: "Update config",
|
||||
operationId: "config.update",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -375,9 +365,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/experimental/tool/ids",
|
||||
describeRoute({
|
||||
summary: "List tool IDs",
|
||||
description:
|
||||
"Get a list of all available tool IDs, including both built-in tools and dynamically registered tools.",
|
||||
description: "List all tool IDs (including built-in and dynamically registered)",
|
||||
operationId: "tool.ids",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -398,9 +386,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/experimental/tool",
|
||||
describeRoute({
|
||||
summary: "List tools",
|
||||
description:
|
||||
"Get a list of available tools with their JSON schema parameters for a specific provider and model combination.",
|
||||
description: "List tools with JSON schema parameters for a provider/model",
|
||||
operationId: "tool.list",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -449,8 +435,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/instance/dispose",
|
||||
describeRoute({
|
||||
summary: "Dispose instance",
|
||||
description: "Clean up and dispose the current OpenCode instance, releasing all resources.",
|
||||
description: "Dispose the current instance",
|
||||
operationId: "instance.dispose",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -471,8 +456,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/path",
|
||||
describeRoute({
|
||||
summary: "Get paths",
|
||||
description: "Retrieve the current working directory and related path information for the OpenCode instance.",
|
||||
description: "Get the current path",
|
||||
operationId: "path.get",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -508,8 +492,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/vcs",
|
||||
describeRoute({
|
||||
summary: "Get VCS info",
|
||||
description: "Retrieve version control system (VCS) information for the current project, such as git branch.",
|
||||
description: "Get VCS info for the current instance",
|
||||
operationId: "vcs.get",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -532,8 +515,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/session",
|
||||
describeRoute({
|
||||
summary: "List sessions",
|
||||
description: "Get a list of all OpenCode sessions, sorted by most recently updated.",
|
||||
description: "List all sessions",
|
||||
operationId: "session.list",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -555,8 +537,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/session/status",
|
||||
describeRoute({
|
||||
summary: "Get session status",
|
||||
description: "Retrieve the current status of all sessions, including active, idle, and completed states.",
|
||||
description: "Get session status",
|
||||
operationId: "session.status",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -578,9 +559,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/session/:sessionID",
|
||||
describeRoute({
|
||||
summary: "Get session",
|
||||
description: "Retrieve detailed information about a specific OpenCode session.",
|
||||
tags: ["Session"],
|
||||
description: "Get session",
|
||||
operationId: "session.get",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -610,9 +589,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/session/:sessionID/children",
|
||||
describeRoute({
|
||||
summary: "Get session children",
|
||||
tags: ["Session"],
|
||||
description: "Retrieve all child sessions that were forked from the specified parent session.",
|
||||
description: "Get a session's children",
|
||||
operationId: "session.children",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -641,8 +618,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/session/:sessionID/todo",
|
||||
describeRoute({
|
||||
summary: "Get session todos",
|
||||
description: "Retrieve the todo list associated with a specific session, showing tasks and action items.",
|
||||
description: "Get the todo list for a session",
|
||||
operationId: "session.todo",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -671,8 +647,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/session",
|
||||
describeRoute({
|
||||
summary: "Create session",
|
||||
description: "Create a new OpenCode session for interacting with AI assistants and managing conversations.",
|
||||
description: "Create a new session",
|
||||
operationId: "session.create",
|
||||
responses: {
|
||||
...errors(400),
|
||||
@@ -696,8 +671,7 @@ export namespace Server {
|
||||
.delete(
|
||||
"/session/:sessionID",
|
||||
describeRoute({
|
||||
summary: "Delete session",
|
||||
description: "Delete a session and permanently remove all associated data, including messages and history.",
|
||||
description: "Delete a session and all its data",
|
||||
operationId: "session.delete",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -729,8 +703,7 @@ export namespace Server {
|
||||
.patch(
|
||||
"/session/:sessionID",
|
||||
describeRoute({
|
||||
summary: "Update session",
|
||||
description: "Update properties of an existing session, such as title or other metadata.",
|
||||
description: "Update session properties",
|
||||
operationId: "session.update",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -772,9 +745,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/session/:sessionID/init",
|
||||
describeRoute({
|
||||
summary: "Initialize session",
|
||||
description:
|
||||
"Analyze the current application and create an AGENTS.md file with project-specific agent configurations.",
|
||||
description: "Analyze the app and create an AGENTS.md file",
|
||||
operationId: "session.init",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -805,8 +776,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/session/:sessionID/fork",
|
||||
describeRoute({
|
||||
summary: "Fork session",
|
||||
description: "Create a new session by forking an existing session at a specific message point.",
|
||||
description: "Fork an existing session at a specific message",
|
||||
operationId: "session.fork",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -836,8 +806,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/session/:sessionID/abort",
|
||||
describeRoute({
|
||||
summary: "Abort session",
|
||||
description: "Abort an active session and stop any ongoing AI processing or command execution.",
|
||||
description: "Abort a session",
|
||||
operationId: "session.abort",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -865,8 +834,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/session/:sessionID/share",
|
||||
describeRoute({
|
||||
summary: "Share session",
|
||||
description: "Create a shareable link for a session, allowing others to view the conversation.",
|
||||
description: "Share a session",
|
||||
operationId: "session.share",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -896,8 +864,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/session/:sessionID/diff",
|
||||
describeRoute({
|
||||
summary: "Get message diff",
|
||||
description: "Get the file changes (diff) that resulted from a specific user message in the session.",
|
||||
description: "Get the diff that resulted from this user message",
|
||||
operationId: "session.diff",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -935,8 +902,7 @@ export namespace Server {
|
||||
.delete(
|
||||
"/session/:sessionID/share",
|
||||
describeRoute({
|
||||
summary: "Unshare session",
|
||||
description: "Remove the shareable link for a session, making it private again.",
|
||||
description: "Unshare the session",
|
||||
operationId: "session.unshare",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -966,8 +932,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/session/:sessionID/summarize",
|
||||
describeRoute({
|
||||
summary: "Summarize session",
|
||||
description: "Generate a concise summary of the session using AI compaction to preserve key information.",
|
||||
description: "Summarize the session",
|
||||
operationId: "session.summarize",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1022,8 +987,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/session/:sessionID/message",
|
||||
describeRoute({
|
||||
summary: "Get session messages",
|
||||
description: "Retrieve all messages in a session, including user prompts and AI responses.",
|
||||
description: "List messages for a session",
|
||||
operationId: "session.messages",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1061,8 +1025,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/session/:sessionID/diff",
|
||||
describeRoute({
|
||||
summary: "Get session diff",
|
||||
description: "Get all file changes (diffs) made during this session.",
|
||||
description: "Get the diff for this session",
|
||||
operationId: "session.diff",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1090,8 +1053,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/session/:sessionID/message/:messageID",
|
||||
describeRoute({
|
||||
summary: "Get message",
|
||||
description: "Retrieve a specific message from a session by its message ID.",
|
||||
description: "Get a message from a session",
|
||||
operationId: "session.message",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1129,8 +1091,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/session/:sessionID/message",
|
||||
describeRoute({
|
||||
summary: "Send message",
|
||||
description: "Create and send a new message to a session, streaming the AI response.",
|
||||
description: "Create and send a new message to a session",
|
||||
operationId: "session.prompt",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1170,9 +1131,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/session/:sessionID/prompt_async",
|
||||
describeRoute({
|
||||
summary: "Send async message",
|
||||
description:
|
||||
"Create and send a new message to a session asynchronously, starting the session if needed and returning immediately.",
|
||||
description: "Create and send a new message to a session, start if needed and return immediately",
|
||||
operationId: "session.prompt_async",
|
||||
responses: {
|
||||
204: {
|
||||
@@ -1201,8 +1160,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/session/:sessionID/command",
|
||||
describeRoute({
|
||||
summary: "Send command",
|
||||
description: "Send a new command to a session for execution by the AI assistant.",
|
||||
description: "Send a new command to a session",
|
||||
operationId: "session.command",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1238,8 +1196,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/session/:sessionID/shell",
|
||||
describeRoute({
|
||||
summary: "Run shell command",
|
||||
description: "Execute a shell command within the session context and return the AI's response.",
|
||||
description: "Run a shell command",
|
||||
operationId: "session.shell",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1270,8 +1227,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/session/:sessionID/revert",
|
||||
describeRoute({
|
||||
summary: "Revert message",
|
||||
description: "Revert a specific message in a session, undoing its effects and restoring the previous state.",
|
||||
description: "Revert a message",
|
||||
operationId: "session.revert",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1305,8 +1261,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/session/:sessionID/unrevert",
|
||||
describeRoute({
|
||||
summary: "Restore reverted messages",
|
||||
description: "Restore all previously reverted messages in a session.",
|
||||
description: "Restore all reverted messages",
|
||||
operationId: "session.unrevert",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1335,8 +1290,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/session/:sessionID/permissions/:permissionID",
|
||||
describeRoute({
|
||||
summary: "Respond to permission",
|
||||
description: "Approve or deny a permission request from the AI assistant.",
|
||||
description: "Respond to a permission request",
|
||||
operationId: "permission.respond",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1373,8 +1327,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/command",
|
||||
describeRoute({
|
||||
summary: "List commands",
|
||||
description: "Get a list of all available commands in the OpenCode system.",
|
||||
description: "List all commands",
|
||||
operationId: "command.list",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1395,8 +1348,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/config/providers",
|
||||
describeRoute({
|
||||
summary: "List config providers",
|
||||
description: "Get a list of all configured AI providers and their default models.",
|
||||
description: "List all providers",
|
||||
operationId: "config.providers",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1426,8 +1378,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/provider",
|
||||
describeRoute({
|
||||
summary: "List providers",
|
||||
description: "Get a list of all available AI providers, including both available and connected ones.",
|
||||
description: "List all providers",
|
||||
operationId: "provider.list",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1447,19 +1398,10 @@ export namespace Server {
|
||||
},
|
||||
}),
|
||||
async (c) => {
|
||||
const config = await Config.get()
|
||||
const disabled = new Set(config.disabled_providers ?? [])
|
||||
const enabled = config.enabled_providers ? new Set(config.enabled_providers) : undefined
|
||||
|
||||
const allProviders = await ModelsDev.get()
|
||||
const filteredProviders: Record<string, (typeof allProviders)[string]> = {}
|
||||
for (const [key, value] of Object.entries(allProviders)) {
|
||||
if ((enabled ? enabled.has(key) : true) && !disabled.has(key)) {
|
||||
filteredProviders[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
const providers = mapValues(filteredProviders, (x) => Provider.fromModelsDevProvider(x))
|
||||
const providers = pipe(
|
||||
await ModelsDev.get(),
|
||||
mapValues((x) => Provider.fromModelsDevProvider(x)),
|
||||
)
|
||||
const connected = await Provider.list().then((x) => Object.keys(x))
|
||||
return c.json({
|
||||
all: Object.values(providers),
|
||||
@@ -1471,8 +1413,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/provider/auth",
|
||||
describeRoute({
|
||||
summary: "Get provider auth methods",
|
||||
description: "Retrieve available authentication methods for all AI providers.",
|
||||
description: "Get provider authentication methods",
|
||||
operationId: "provider.auth",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1492,8 +1433,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/provider/:providerID/oauth/authorize",
|
||||
describeRoute({
|
||||
summary: "OAuth authorize",
|
||||
description: "Initiate OAuth authorization for a specific AI provider to get an authorization URL.",
|
||||
description: "Authorize a provider using OAuth",
|
||||
operationId: "provider.oauth.authorize",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1532,8 +1472,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/provider/:providerID/oauth/callback",
|
||||
describeRoute({
|
||||
summary: "OAuth callback",
|
||||
description: "Handle the OAuth callback from a provider after user authorization.",
|
||||
description: "Handle OAuth callback for a provider",
|
||||
operationId: "provider.oauth.callback",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1574,8 +1513,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/find",
|
||||
describeRoute({
|
||||
summary: "Find text",
|
||||
description: "Search for text patterns across files in the project using ripgrep.",
|
||||
description: "Find text in files",
|
||||
operationId: "find.text",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1607,8 +1545,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/find/file",
|
||||
describeRoute({
|
||||
summary: "Find files",
|
||||
description: "Search for files by name or pattern in the project directory.",
|
||||
description: "Find files",
|
||||
operationId: "find.files",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1642,8 +1579,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/find/symbol",
|
||||
describeRoute({
|
||||
summary: "Find symbols",
|
||||
description: "Search for workspace symbols like functions, classes, and variables using LSP.",
|
||||
description: "Find workspace symbols",
|
||||
operationId: "find.symbols",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1674,8 +1610,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/file",
|
||||
describeRoute({
|
||||
summary: "List files",
|
||||
description: "List files and directories in a specified path.",
|
||||
description: "List files and directories",
|
||||
operationId: "file.list",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1703,8 +1638,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/file/content",
|
||||
describeRoute({
|
||||
summary: "Read file",
|
||||
description: "Read the content of a specified file.",
|
||||
description: "Read a file",
|
||||
operationId: "file.read",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1732,8 +1666,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/file/status",
|
||||
describeRoute({
|
||||
summary: "Get file status",
|
||||
description: "Get the git status of all files in the project.",
|
||||
description: "Get file status",
|
||||
operationId: "file.status",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1754,8 +1687,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/log",
|
||||
describeRoute({
|
||||
summary: "Write log",
|
||||
description: "Write a log entry to the server logs with specified level and metadata.",
|
||||
description: "Write a log entry to the server logs",
|
||||
operationId: "app.log",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1806,8 +1738,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/agent",
|
||||
describeRoute({
|
||||
summary: "List agents",
|
||||
description: "Get a list of all available AI agents in the OpenCode system.",
|
||||
description: "List all agents",
|
||||
operationId: "app.agents",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1828,8 +1759,7 @@ export namespace Server {
|
||||
.get(
|
||||
"/mcp",
|
||||
describeRoute({
|
||||
summary: "Get MCP status",
|
||||
description: "Get the status of all Model Context Protocol (MCP) servers.",
|
||||
description: "Get MCP server status",
|
||||
operationId: "mcp.status",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1849,8 +1779,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/mcp",
|
||||
describeRoute({
|
||||
summary: "Add MCP server",
|
||||
description: "Dynamically add a new Model Context Protocol (MCP) server to the system.",
|
||||
description: "Add MCP server dynamically",
|
||||
operationId: "mcp.add",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1880,8 +1809,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/mcp/:name/auth",
|
||||
describeRoute({
|
||||
summary: "Start MCP OAuth",
|
||||
description: "Start OAuth authentication flow for a Model Context Protocol (MCP) server.",
|
||||
description: "Start OAuth authentication flow for an MCP server",
|
||||
operationId: "mcp.auth.start",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1912,9 +1840,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/mcp/:name/auth/callback",
|
||||
describeRoute({
|
||||
summary: "Complete MCP OAuth",
|
||||
description:
|
||||
"Complete OAuth authentication for a Model Context Protocol (MCP) server using the authorization code.",
|
||||
description: "Complete OAuth authentication with authorization code",
|
||||
operationId: "mcp.auth.callback",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -1944,7 +1870,6 @@ export namespace Server {
|
||||
.post(
|
||||
"/mcp/:name/auth/authenticate",
|
||||
describeRoute({
|
||||
summary: "Authenticate MCP OAuth",
|
||||
description: "Start OAuth flow and wait for callback (opens browser)",
|
||||
operationId: "mcp.auth.authenticate",
|
||||
responses: {
|
||||
@@ -1972,7 +1897,6 @@ export namespace Server {
|
||||
.delete(
|
||||
"/mcp/:name/auth",
|
||||
describeRoute({
|
||||
summary: "Remove MCP OAuth",
|
||||
description: "Remove OAuth credentials for an MCP server",
|
||||
operationId: "mcp.auth.remove",
|
||||
responses: {
|
||||
@@ -1993,56 +1917,9 @@ export namespace Server {
|
||||
return c.json({ success: true as const })
|
||||
},
|
||||
)
|
||||
.post(
|
||||
"/mcp/:name/connect",
|
||||
describeRoute({
|
||||
description: "Connect an MCP server",
|
||||
operationId: "mcp.connect",
|
||||
responses: {
|
||||
200: {
|
||||
description: "MCP server connected successfully",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(z.boolean()),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
validator("param", z.object({ name: z.string() })),
|
||||
async (c) => {
|
||||
const { name } = c.req.valid("param")
|
||||
await MCP.connect(name)
|
||||
return c.json(true)
|
||||
},
|
||||
)
|
||||
.post(
|
||||
"/mcp/:name/disconnect",
|
||||
describeRoute({
|
||||
description: "Disconnect an MCP server",
|
||||
operationId: "mcp.disconnect",
|
||||
responses: {
|
||||
200: {
|
||||
description: "MCP server disconnected successfully",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(z.boolean()),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
validator("param", z.object({ name: z.string() })),
|
||||
async (c) => {
|
||||
const { name } = c.req.valid("param")
|
||||
await MCP.disconnect(name)
|
||||
return c.json(true)
|
||||
},
|
||||
)
|
||||
.get(
|
||||
"/lsp",
|
||||
describeRoute({
|
||||
summary: "Get LSP status",
|
||||
description: "Get LSP server status",
|
||||
operationId: "lsp.status",
|
||||
responses: {
|
||||
@@ -2063,7 +1940,6 @@ export namespace Server {
|
||||
.get(
|
||||
"/formatter",
|
||||
describeRoute({
|
||||
summary: "Get formatter status",
|
||||
description: "Get formatter status",
|
||||
operationId: "formatter.status",
|
||||
responses: {
|
||||
@@ -2084,7 +1960,6 @@ export namespace Server {
|
||||
.post(
|
||||
"/tui/append-prompt",
|
||||
describeRoute({
|
||||
summary: "Append TUI prompt",
|
||||
description: "Append prompt to the TUI",
|
||||
operationId: "tui.appendPrompt",
|
||||
responses: {
|
||||
@@ -2108,8 +1983,7 @@ export namespace Server {
|
||||
.post(
|
||||
"/tui/open-help",
|
||||
describeRoute({
|
||||
summary: "Open help dialog",
|
||||
description: "Open the help dialog in the TUI to display user assistance information.",
|
||||
description: "Open the help dialog",
|
||||
operationId: "tui.openHelp",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -2130,7 +2004,6 @@ export namespace Server {
|
||||
.post(
|
||||
"/tui/open-sessions",
|
||||
describeRoute({
|
||||
summary: "Open sessions dialog",
|
||||
description: "Open the session dialog",
|
||||
operationId: "tui.openSessions",
|
||||
responses: {
|
||||
@@ -2154,7 +2027,6 @@ export namespace Server {
|
||||
.post(
|
||||
"/tui/open-themes",
|
||||
describeRoute({
|
||||
summary: "Open themes dialog",
|
||||
description: "Open the theme dialog",
|
||||
operationId: "tui.openThemes",
|
||||
responses: {
|
||||
@@ -2178,7 +2050,6 @@ export namespace Server {
|
||||
.post(
|
||||
"/tui/open-models",
|
||||
describeRoute({
|
||||
summary: "Open models dialog",
|
||||
description: "Open the model dialog",
|
||||
operationId: "tui.openModels",
|
||||
responses: {
|
||||
@@ -2202,7 +2073,6 @@ export namespace Server {
|
||||
.post(
|
||||
"/tui/submit-prompt",
|
||||
describeRoute({
|
||||
summary: "Submit TUI prompt",
|
||||
description: "Submit the prompt",
|
||||
operationId: "tui.submitPrompt",
|
||||
responses: {
|
||||
@@ -2226,7 +2096,6 @@ export namespace Server {
|
||||
.post(
|
||||
"/tui/clear-prompt",
|
||||
describeRoute({
|
||||
summary: "Clear TUI prompt",
|
||||
description: "Clear the prompt",
|
||||
operationId: "tui.clearPrompt",
|
||||
responses: {
|
||||
@@ -2250,7 +2119,6 @@ export namespace Server {
|
||||
.post(
|
||||
"/tui/execute-command",
|
||||
describeRoute({
|
||||
summary: "Execute TUI command",
|
||||
description: "Execute a TUI command (e.g. agent_cycle)",
|
||||
operationId: "tui.executeCommand",
|
||||
responses: {
|
||||
@@ -2290,7 +2158,6 @@ export namespace Server {
|
||||
.post(
|
||||
"/tui/show-toast",
|
||||
describeRoute({
|
||||
summary: "Show TUI toast",
|
||||
description: "Show a toast notification in the TUI",
|
||||
operationId: "tui.showToast",
|
||||
responses: {
|
||||
@@ -2313,7 +2180,6 @@ export namespace Server {
|
||||
.post(
|
||||
"/tui/publish",
|
||||
describeRoute({
|
||||
summary: "Publish TUI event",
|
||||
description: "Publish a TUI event",
|
||||
operationId: "tui.publish",
|
||||
responses: {
|
||||
@@ -2353,7 +2219,6 @@ export namespace Server {
|
||||
.put(
|
||||
"/auth/:providerID",
|
||||
describeRoute({
|
||||
summary: "Set auth credentials",
|
||||
description: "Set authentication credentials",
|
||||
operationId: "auth.set",
|
||||
responses: {
|
||||
@@ -2385,7 +2250,6 @@ export namespace Server {
|
||||
.get(
|
||||
"/event",
|
||||
describeRoute({
|
||||
summary: "Subscribe to events",
|
||||
description: "Get events",
|
||||
operationId: "event.subscribe",
|
||||
responses: {
|
||||
@@ -2427,10 +2291,10 @@ export namespace Server {
|
||||
},
|
||||
)
|
||||
.all("/*", async (c) => {
|
||||
return proxy(`https://desktop.opencode.ai${c.req.path}`, {
|
||||
return proxy(`https://desktop.dev.opencode.ai${c.req.path}`, {
|
||||
...c.req,
|
||||
headers: {
|
||||
host: "desktop.opencode.ai",
|
||||
host: "desktop.dev.opencode.ai",
|
||||
},
|
||||
})
|
||||
}),
|
||||
|
||||
@@ -26,8 +26,7 @@ export const TuiRoute = new Hono()
|
||||
.get(
|
||||
"/next",
|
||||
describeRoute({
|
||||
summary: "Get next TUI request",
|
||||
description: "Retrieve the next TUI (Terminal User Interface) request from the queue for processing.",
|
||||
description: "Get the next TUI request from the queue",
|
||||
operationId: "tui.control.next",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -48,8 +47,7 @@ export const TuiRoute = new Hono()
|
||||
.post(
|
||||
"/response",
|
||||
describeRoute({
|
||||
summary: "Submit TUI response",
|
||||
description: "Submit a response to the TUI request queue to complete a pending request.",
|
||||
description: "Submit a response to the TUI request queue",
|
||||
operationId: "tui.control.response",
|
||||
responses: {
|
||||
200: {
|
||||
|
||||
@@ -411,6 +411,147 @@ export namespace MessageV2 {
|
||||
})
|
||||
export type WithParts = z.infer<typeof WithParts>
|
||||
|
||||
export function fromV1(v1: Message.Info) {
|
||||
if (v1.role === "assistant") {
|
||||
const info: Assistant = {
|
||||
id: v1.id,
|
||||
parentID: "",
|
||||
sessionID: v1.metadata.sessionID,
|
||||
role: "assistant",
|
||||
time: {
|
||||
created: v1.metadata.time.created,
|
||||
completed: v1.metadata.time.completed,
|
||||
},
|
||||
cost: v1.metadata.assistant!.cost,
|
||||
path: v1.metadata.assistant!.path,
|
||||
summary: v1.metadata.assistant!.summary,
|
||||
tokens: v1.metadata.assistant!.tokens,
|
||||
modelID: v1.metadata.assistant!.modelID,
|
||||
providerID: v1.metadata.assistant!.providerID,
|
||||
mode: "build",
|
||||
error: v1.metadata.error,
|
||||
}
|
||||
const parts = v1.parts.flatMap((part): Part[] => {
|
||||
const base = {
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: v1.id,
|
||||
sessionID: v1.metadata.sessionID,
|
||||
}
|
||||
if (part.type === "text") {
|
||||
return [
|
||||
{
|
||||
...base,
|
||||
type: "text",
|
||||
text: part.text,
|
||||
},
|
||||
]
|
||||
}
|
||||
if (part.type === "step-start") {
|
||||
return [
|
||||
{
|
||||
...base,
|
||||
type: "step-start",
|
||||
},
|
||||
]
|
||||
}
|
||||
if (part.type === "tool-invocation") {
|
||||
return [
|
||||
{
|
||||
...base,
|
||||
type: "tool",
|
||||
callID: part.toolInvocation.toolCallId,
|
||||
tool: part.toolInvocation.toolName,
|
||||
state: (() => {
|
||||
if (part.toolInvocation.state === "partial-call") {
|
||||
return {
|
||||
status: "pending",
|
||||
input: {},
|
||||
raw: "",
|
||||
}
|
||||
}
|
||||
|
||||
const { title, time, ...metadata } = v1.metadata.tool[part.toolInvocation.toolCallId] ?? {}
|
||||
if (part.toolInvocation.state === "call") {
|
||||
return {
|
||||
status: "running",
|
||||
input: part.toolInvocation.args,
|
||||
time: {
|
||||
start: time?.start,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (part.toolInvocation.state === "result") {
|
||||
return {
|
||||
status: "completed",
|
||||
input: part.toolInvocation.args,
|
||||
output: part.toolInvocation.result,
|
||||
title,
|
||||
time,
|
||||
metadata,
|
||||
}
|
||||
}
|
||||
throw new Error("unknown tool invocation state")
|
||||
})(),
|
||||
},
|
||||
]
|
||||
}
|
||||
return []
|
||||
})
|
||||
return {
|
||||
info,
|
||||
parts,
|
||||
}
|
||||
}
|
||||
|
||||
if (v1.role === "user") {
|
||||
const info: User = {
|
||||
id: v1.id,
|
||||
sessionID: v1.metadata.sessionID,
|
||||
role: "user",
|
||||
time: {
|
||||
created: v1.metadata.time.created,
|
||||
},
|
||||
agent: "build",
|
||||
model: {
|
||||
providerID: "opencode",
|
||||
modelID: "opencode",
|
||||
},
|
||||
}
|
||||
const parts = v1.parts.flatMap((part): Part[] => {
|
||||
const base = {
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: v1.id,
|
||||
sessionID: v1.metadata.sessionID,
|
||||
}
|
||||
if (part.type === "text") {
|
||||
return [
|
||||
{
|
||||
...base,
|
||||
type: "text",
|
||||
text: part.text,
|
||||
},
|
||||
]
|
||||
}
|
||||
if (part.type === "file") {
|
||||
return [
|
||||
{
|
||||
...base,
|
||||
type: "file",
|
||||
mime: part.mediaType,
|
||||
filename: part.filename,
|
||||
url: part.url,
|
||||
},
|
||||
]
|
||||
}
|
||||
return []
|
||||
})
|
||||
return { info, parts }
|
||||
}
|
||||
|
||||
throw new Error("unknown message type")
|
||||
}
|
||||
|
||||
export function toModelMessage(
|
||||
input: {
|
||||
info: Info
|
||||
@@ -613,7 +754,7 @@ export namespace MessageV2 {
|
||||
try {
|
||||
const body = JSON.parse(e.responseBody)
|
||||
// try to extract common error message fields
|
||||
const errMsg = body.message || body.error || body.error?.message
|
||||
const errMsg = body.message || body.error
|
||||
if (errMsg && typeof errMsg === "string") {
|
||||
return `${msg}: ${errMsg}`
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import { SessionSummary } from "./summary"
|
||||
import { Bus } from "@/bus"
|
||||
import { SessionRetry } from "./retry"
|
||||
import { SessionStatus } from "./status"
|
||||
import { Plugin } from "@/plugin"
|
||||
import type { Provider } from "@/provider/provider"
|
||||
|
||||
export namespace SessionProcessor {
|
||||
@@ -317,16 +316,6 @@ export namespace SessionProcessor {
|
||||
case "text-end":
|
||||
if (currentText) {
|
||||
currentText.text = currentText.text.trimEnd()
|
||||
const textOutput = await Plugin.trigger(
|
||||
"experimental.text.complete",
|
||||
{
|
||||
sessionID: input.sessionID,
|
||||
messageID: input.assistantMessage.id,
|
||||
partID: currentText.id,
|
||||
},
|
||||
{ text: currentText.text },
|
||||
)
|
||||
currentText.text = textOutput.text
|
||||
currentText.time = {
|
||||
start: Date.now(),
|
||||
end: Date.now(),
|
||||
|
||||
@@ -7,6 +7,7 @@ import { FileTime } from "../file/time"
|
||||
import DESCRIPTION from "./read.txt"
|
||||
import { Filesystem } from "../util/filesystem"
|
||||
import { Instance } from "../project/instance"
|
||||
import { Provider } from "../provider/provider"
|
||||
import { Identifier } from "../id/id"
|
||||
import { Permission } from "../permission"
|
||||
import { Agent } from "@/agent/agent"
|
||||
@@ -93,11 +94,15 @@ export const ReadTool = Tool.define("read", {
|
||||
throw new Error(`File not found: ${filepath}`)
|
||||
}
|
||||
|
||||
const isImage = file.type.startsWith("image/")
|
||||
const isPdf = file.type === "application/pdf"
|
||||
if (isImage || isPdf) {
|
||||
const isImage = isImageFile(filepath)
|
||||
const model = ctx.extra?.model as Provider.Model | undefined
|
||||
const supportsImages = model?.capabilities.input.image ?? false
|
||||
if (isImage) {
|
||||
if (!supportsImages) {
|
||||
throw new Error(`Failed to read image: ${filepath}, model may not be able to read images`)
|
||||
}
|
||||
const mime = file.type
|
||||
const msg = `${isImage ? "Image" : "PDF"} read successfully`
|
||||
const msg = "Image read successfully"
|
||||
return {
|
||||
title,
|
||||
output: msg,
|
||||
@@ -159,6 +164,25 @@ export const ReadTool = Tool.define("read", {
|
||||
},
|
||||
})
|
||||
|
||||
function isImageFile(filePath: string): string | false {
|
||||
const ext = path.extname(filePath).toLowerCase()
|
||||
switch (ext) {
|
||||
case ".jpg":
|
||||
case ".jpeg":
|
||||
return "JPEG"
|
||||
case ".png":
|
||||
return "PNG"
|
||||
case ".gif":
|
||||
return "GIF"
|
||||
case ".bmp":
|
||||
return "BMP"
|
||||
case ".webp":
|
||||
return "WebP"
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function isBinaryFile(filepath: string, file: Bun.BunFile): Promise<boolean> {
|
||||
const ext = path.extname(filepath).toLowerCase()
|
||||
// binary check for common non-text extensions
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit",
|
||||
|
||||
@@ -175,8 +175,4 @@ export interface Hooks {
|
||||
metadata: any
|
||||
},
|
||||
) => Promise<void>
|
||||
"experimental.text.complete"?: (
|
||||
input: { sessionID: string; messageID: string; partID: string },
|
||||
output: { text: string },
|
||||
) => Promise<void>
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit",
|
||||
|
||||
@@ -160,10 +160,6 @@ import type {
|
||||
McpAuthAuthenticateData,
|
||||
McpAuthAuthenticateResponses,
|
||||
McpAuthAuthenticateErrors,
|
||||
McpConnectData,
|
||||
McpConnectResponses,
|
||||
McpDisconnectData,
|
||||
McpDisconnectResponses,
|
||||
LspStatusData,
|
||||
LspStatusResponses,
|
||||
FormatterStatusData,
|
||||
@@ -949,27 +945,6 @@ class Mcp extends _HeyApiClient {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect an MCP server
|
||||
*/
|
||||
public connect<ThrowOnError extends boolean = false>(options: Options<McpConnectData, ThrowOnError>) {
|
||||
return (options.client ?? this._client).post<McpConnectResponses, unknown, ThrowOnError>({
|
||||
url: "/mcp/{name}/connect",
|
||||
...options,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect an MCP server
|
||||
*/
|
||||
public disconnect<ThrowOnError extends boolean = false>(options: Options<McpDisconnectData, ThrowOnError>) {
|
||||
return (options.client ?? this._client).post<McpDisconnectResponses, unknown, ThrowOnError>({
|
||||
url: "/mcp/{name}/disconnect",
|
||||
...options,
|
||||
})
|
||||
}
|
||||
|
||||
auth = new Auth({ client: this._client })
|
||||
}
|
||||
|
||||
|
||||
@@ -3494,46 +3494,6 @@ export type McpAuthAuthenticateResponses = {
|
||||
|
||||
export type McpAuthAuthenticateResponse = McpAuthAuthenticateResponses[keyof McpAuthAuthenticateResponses]
|
||||
|
||||
export type McpConnectData = {
|
||||
body?: never
|
||||
path: {
|
||||
name: string
|
||||
}
|
||||
query?: {
|
||||
directory?: string
|
||||
}
|
||||
url: "/mcp/{name}/connect"
|
||||
}
|
||||
|
||||
export type McpConnectResponses = {
|
||||
/**
|
||||
* MCP server connected successfully
|
||||
*/
|
||||
200: boolean
|
||||
}
|
||||
|
||||
export type McpConnectResponse = McpConnectResponses[keyof McpConnectResponses]
|
||||
|
||||
export type McpDisconnectData = {
|
||||
body?: never
|
||||
path: {
|
||||
name: string
|
||||
}
|
||||
query?: {
|
||||
directory?: string
|
||||
}
|
||||
url: "/mcp/{name}/disconnect"
|
||||
}
|
||||
|
||||
export type McpDisconnectResponses = {
|
||||
/**
|
||||
* MCP server disconnected successfully
|
||||
*/
|
||||
200: boolean
|
||||
}
|
||||
|
||||
export type McpDisconnectResponse = McpDisconnectResponses[keyof McpDisconnectResponses]
|
||||
|
||||
export type LspStatusData = {
|
||||
body?: never
|
||||
path?: never
|
||||
|
||||
@@ -41,8 +41,6 @@ import type {
|
||||
McpAuthRemoveResponses,
|
||||
McpAuthStartErrors,
|
||||
McpAuthStartResponses,
|
||||
McpConnectResponses,
|
||||
McpDisconnectResponses,
|
||||
McpLocalConfig,
|
||||
McpRemoteConfig,
|
||||
McpStatusResponses,
|
||||
@@ -181,9 +179,7 @@ class HeyApiRegistry<T> {
|
||||
|
||||
export class Global extends HeyApiClient {
|
||||
/**
|
||||
* Get global events
|
||||
*
|
||||
* Subscribe to global events from the OpenCode system using server-sent events.
|
||||
* Get events
|
||||
*/
|
||||
public event<ThrowOnError extends boolean = false>(options?: Options<never, ThrowOnError>) {
|
||||
return (options?.client ?? this.client).sse.get<GlobalEventResponses, unknown, ThrowOnError>({
|
||||
@@ -196,8 +192,6 @@ export class Global extends HeyApiClient {
|
||||
export class Project extends HeyApiClient {
|
||||
/**
|
||||
* List all projects
|
||||
*
|
||||
* Get a list of projects that have been opened with OpenCode.
|
||||
*/
|
||||
public list<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -214,9 +208,7 @@ export class Project extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current project
|
||||
*
|
||||
* Retrieve the currently active project that OpenCode is working with.
|
||||
* Get the current project
|
||||
*/
|
||||
public current<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -235,9 +227,7 @@ export class Project extends HeyApiClient {
|
||||
|
||||
export class Pty extends HeyApiClient {
|
||||
/**
|
||||
* List PTY sessions
|
||||
*
|
||||
* Get a list of all active pseudo-terminal (PTY) sessions managed by OpenCode.
|
||||
* List all PTY sessions
|
||||
*/
|
||||
public list<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -254,9 +244,7 @@ export class Pty extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create PTY session
|
||||
*
|
||||
* Create a new pseudo-terminal (PTY) session for running shell commands and processes.
|
||||
* Create a new PTY session
|
||||
*/
|
||||
public create<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -299,9 +287,7 @@ export class Pty extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove PTY session
|
||||
*
|
||||
* Remove and terminate a specific pseudo-terminal (PTY) session.
|
||||
* Remove a PTY session
|
||||
*/
|
||||
public remove<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -329,9 +315,7 @@ export class Pty extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PTY session
|
||||
*
|
||||
* Retrieve detailed information about a specific pseudo-terminal (PTY) session.
|
||||
* Get PTY session info
|
||||
*/
|
||||
public get<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -360,8 +344,6 @@ export class Pty extends HeyApiClient {
|
||||
|
||||
/**
|
||||
* Update PTY session
|
||||
*
|
||||
* Update properties of an existing pseudo-terminal (PTY) session.
|
||||
*/
|
||||
public update<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -401,9 +383,7 @@ export class Pty extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to PTY session
|
||||
*
|
||||
* Establish a WebSocket connection to interact with a pseudo-terminal (PTY) session in real-time.
|
||||
* Connect to a PTY session
|
||||
*/
|
||||
public connect<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -433,9 +413,7 @@ export class Pty extends HeyApiClient {
|
||||
|
||||
export class Config extends HeyApiClient {
|
||||
/**
|
||||
* Get configuration
|
||||
*
|
||||
* Retrieve the current OpenCode configuration settings and preferences.
|
||||
* Get config info
|
||||
*/
|
||||
public get<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -452,9 +430,7 @@ export class Config extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update configuration
|
||||
*
|
||||
* Update OpenCode configuration settings and preferences.
|
||||
* Update config
|
||||
*/
|
||||
public update<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -487,9 +463,7 @@ export class Config extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* List config providers
|
||||
*
|
||||
* Get a list of all configured AI providers and their default models.
|
||||
* List all providers
|
||||
*/
|
||||
public providers<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -508,9 +482,7 @@ export class Config extends HeyApiClient {
|
||||
|
||||
export class Tool extends HeyApiClient {
|
||||
/**
|
||||
* List tool IDs
|
||||
*
|
||||
* Get a list of all available tool IDs, including both built-in tools and dynamically registered tools.
|
||||
* List all tool IDs (including built-in and dynamically registered)
|
||||
*/
|
||||
public ids<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -527,9 +499,7 @@ export class Tool extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* List tools
|
||||
*
|
||||
* Get a list of available tools with their JSON schema parameters for a specific provider and model combination.
|
||||
* List tools with JSON schema parameters for a provider/model
|
||||
*/
|
||||
public list<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -561,9 +531,7 @@ export class Tool extends HeyApiClient {
|
||||
|
||||
export class Instance extends HeyApiClient {
|
||||
/**
|
||||
* Dispose instance
|
||||
*
|
||||
* Clean up and dispose the current OpenCode instance, releasing all resources.
|
||||
* Dispose the current instance
|
||||
*/
|
||||
public dispose<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -582,9 +550,7 @@ export class Instance extends HeyApiClient {
|
||||
|
||||
export class Path extends HeyApiClient {
|
||||
/**
|
||||
* Get paths
|
||||
*
|
||||
* Retrieve the current working directory and related path information for the OpenCode instance.
|
||||
* Get the current path
|
||||
*/
|
||||
public get<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -603,9 +569,7 @@ export class Path extends HeyApiClient {
|
||||
|
||||
export class Vcs extends HeyApiClient {
|
||||
/**
|
||||
* Get VCS info
|
||||
*
|
||||
* Retrieve version control system (VCS) information for the current project, such as git branch.
|
||||
* Get VCS info for the current instance
|
||||
*/
|
||||
public get<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -624,9 +588,7 @@ export class Vcs extends HeyApiClient {
|
||||
|
||||
export class Session extends HeyApiClient {
|
||||
/**
|
||||
* List sessions
|
||||
*
|
||||
* Get a list of all OpenCode sessions, sorted by most recently updated.
|
||||
* List all sessions
|
||||
*/
|
||||
public list<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -643,9 +605,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create session
|
||||
*
|
||||
* Create a new OpenCode session for interacting with AI assistants and managing conversations.
|
||||
* Create a new session
|
||||
*/
|
||||
public create<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -681,8 +641,6 @@ export class Session extends HeyApiClient {
|
||||
|
||||
/**
|
||||
* Get session status
|
||||
*
|
||||
* Retrieve the current status of all sessions, including active, idle, and completed states.
|
||||
*/
|
||||
public status<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -699,9 +657,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete session
|
||||
*
|
||||
* Delete a session and permanently remove all associated data, including messages and history.
|
||||
* Delete a session and all its data
|
||||
*/
|
||||
public delete<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -730,8 +686,6 @@ export class Session extends HeyApiClient {
|
||||
|
||||
/**
|
||||
* Get session
|
||||
*
|
||||
* Retrieve detailed information about a specific OpenCode session.
|
||||
*/
|
||||
public get<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -759,9 +713,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update session
|
||||
*
|
||||
* Update properties of an existing session, such as title or other metadata.
|
||||
* Update session properties
|
||||
*/
|
||||
public update<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -796,9 +748,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get session children
|
||||
*
|
||||
* Retrieve all child sessions that were forked from the specified parent session.
|
||||
* Get a session's children
|
||||
*/
|
||||
public children<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -826,9 +776,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get session todos
|
||||
*
|
||||
* Retrieve the todo list associated with a specific session, showing tasks and action items.
|
||||
* Get the todo list for a session
|
||||
*/
|
||||
public todo<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -856,9 +804,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize session
|
||||
*
|
||||
* Analyze the current application and create an AGENTS.md file with project-specific agent configurations.
|
||||
* Analyze the app and create an AGENTS.md file
|
||||
*/
|
||||
public init<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -897,9 +843,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fork session
|
||||
*
|
||||
* Create a new session by forking an existing session at a specific message point.
|
||||
* Fork an existing session at a specific message
|
||||
*/
|
||||
public fork<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -934,9 +878,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort session
|
||||
*
|
||||
* Abort an active session and stop any ongoing AI processing or command execution.
|
||||
* Abort a session
|
||||
*/
|
||||
public abort<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -964,9 +906,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Unshare session
|
||||
*
|
||||
* Remove the shareable link for a session, making it private again.
|
||||
* Unshare the session
|
||||
*/
|
||||
public unshare<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -994,9 +934,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Share session
|
||||
*
|
||||
* Create a shareable link for a session, allowing others to view the conversation.
|
||||
* Share a session
|
||||
*/
|
||||
public share<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1024,9 +962,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get session diff
|
||||
*
|
||||
* Get all file changes (diffs) made during this session.
|
||||
* Get the diff for this session
|
||||
*/
|
||||
public diff<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1056,9 +992,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Summarize session
|
||||
*
|
||||
* Generate a concise summary of the session using AI compaction to preserve key information.
|
||||
* Summarize the session
|
||||
*/
|
||||
public summarize<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1095,9 +1029,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get session messages
|
||||
*
|
||||
* Retrieve all messages in a session, including user prompts and AI responses.
|
||||
* List messages for a session
|
||||
*/
|
||||
public messages<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1127,9 +1059,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Send message
|
||||
*
|
||||
* Create and send a new message to a session, streaming the AI response.
|
||||
* Create and send a new message to a session
|
||||
*/
|
||||
public prompt<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1181,9 +1111,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get message
|
||||
*
|
||||
* Retrieve a specific message from a session by its message ID.
|
||||
* Get a message from a session
|
||||
*/
|
||||
public message<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1213,9 +1141,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Send async message
|
||||
*
|
||||
* Create and send a new message to a session asynchronously, starting the session if needed and returning immediately.
|
||||
* Create and send a new message to a session, start if needed and return immediately
|
||||
*/
|
||||
public promptAsync<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1267,9 +1193,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Send command
|
||||
*
|
||||
* Send a new command to a session for execution by the AI assistant.
|
||||
* Send a new command to a session
|
||||
*/
|
||||
public command<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1312,9 +1236,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Run shell command
|
||||
*
|
||||
* Execute a shell command within the session context and return the AI's response.
|
||||
* Run a shell command
|
||||
*/
|
||||
public shell<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1356,9 +1278,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert message
|
||||
*
|
||||
* Revert a specific message in a session, undoing its effects and restoring the previous state.
|
||||
* Revert a message
|
||||
*/
|
||||
public revert<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1395,9 +1315,7 @@ export class Session extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore reverted messages
|
||||
*
|
||||
* Restore all previously reverted messages in a session.
|
||||
* Restore all reverted messages
|
||||
*/
|
||||
public unrevert<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1427,9 +1345,7 @@ export class Session extends HeyApiClient {
|
||||
|
||||
export class Permission extends HeyApiClient {
|
||||
/**
|
||||
* Respond to permission
|
||||
*
|
||||
* Approve or deny a permission request from the AI assistant.
|
||||
* Respond to a permission request
|
||||
*/
|
||||
public respond<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1468,9 +1384,7 @@ export class Permission extends HeyApiClient {
|
||||
|
||||
export class Command extends HeyApiClient {
|
||||
/**
|
||||
* List commands
|
||||
*
|
||||
* Get a list of all available commands in the OpenCode system.
|
||||
* List all commands
|
||||
*/
|
||||
public list<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -1489,9 +1403,7 @@ export class Command extends HeyApiClient {
|
||||
|
||||
export class Oauth extends HeyApiClient {
|
||||
/**
|
||||
* OAuth authorize
|
||||
*
|
||||
* Initiate OAuth authorization for a specific AI provider to get an authorization URL.
|
||||
* Authorize a provider using OAuth
|
||||
*/
|
||||
public authorize<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1530,9 +1442,7 @@ export class Oauth extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* OAuth callback
|
||||
*
|
||||
* Handle the OAuth callback from a provider after user authorization.
|
||||
* Handle OAuth callback for a provider
|
||||
*/
|
||||
public callback<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1575,9 +1485,7 @@ export class Oauth extends HeyApiClient {
|
||||
|
||||
export class Provider extends HeyApiClient {
|
||||
/**
|
||||
* List providers
|
||||
*
|
||||
* Get a list of all available AI providers, including both available and connected ones.
|
||||
* List all providers
|
||||
*/
|
||||
public list<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -1594,9 +1502,7 @@ export class Provider extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get provider auth methods
|
||||
*
|
||||
* Retrieve available authentication methods for all AI providers.
|
||||
* Get provider authentication methods
|
||||
*/
|
||||
public auth<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -1617,9 +1523,7 @@ export class Provider extends HeyApiClient {
|
||||
|
||||
export class Find extends HeyApiClient {
|
||||
/**
|
||||
* Find text
|
||||
*
|
||||
* Search for text patterns across files in the project using ripgrep.
|
||||
* Find text in files
|
||||
*/
|
||||
public text<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1648,8 +1552,6 @@ export class Find extends HeyApiClient {
|
||||
|
||||
/**
|
||||
* Find files
|
||||
*
|
||||
* Search for files by name or pattern in the project directory.
|
||||
*/
|
||||
public files<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1679,9 +1581,7 @@ export class Find extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find symbols
|
||||
*
|
||||
* Search for workspace symbols like functions, classes, and variables using LSP.
|
||||
* Find workspace symbols
|
||||
*/
|
||||
public symbols<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1711,9 +1611,7 @@ export class Find extends HeyApiClient {
|
||||
|
||||
export class File extends HeyApiClient {
|
||||
/**
|
||||
* List files
|
||||
*
|
||||
* List files and directories in a specified path.
|
||||
* List files and directories
|
||||
*/
|
||||
public list<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1741,9 +1639,7 @@ export class File extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Read file
|
||||
*
|
||||
* Read the content of a specified file.
|
||||
* Read a file
|
||||
*/
|
||||
public read<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1772,8 +1668,6 @@ export class File extends HeyApiClient {
|
||||
|
||||
/**
|
||||
* Get file status
|
||||
*
|
||||
* Get the git status of all files in the project.
|
||||
*/
|
||||
public status<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -1792,9 +1686,7 @@ export class File extends HeyApiClient {
|
||||
|
||||
export class App extends HeyApiClient {
|
||||
/**
|
||||
* Write log
|
||||
*
|
||||
* Write a log entry to the server logs with specified level and metadata.
|
||||
* Write a log entry to the server logs
|
||||
*/
|
||||
public log<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -1835,9 +1727,7 @@ export class App extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* List agents
|
||||
*
|
||||
* Get a list of all available AI agents in the OpenCode system.
|
||||
* List all agents
|
||||
*/
|
||||
public agents<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -1856,8 +1746,6 @@ export class App extends HeyApiClient {
|
||||
|
||||
export class Auth extends HeyApiClient {
|
||||
/**
|
||||
* Remove MCP OAuth
|
||||
*
|
||||
* Remove OAuth credentials for an MCP server
|
||||
*/
|
||||
public remove<ThrowOnError extends boolean = false>(
|
||||
@@ -1886,9 +1774,7 @@ export class Auth extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Start MCP OAuth
|
||||
*
|
||||
* Start OAuth authentication flow for a Model Context Protocol (MCP) server.
|
||||
* Start OAuth authentication flow for an MCP server
|
||||
*/
|
||||
public start<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1916,9 +1802,7 @@ export class Auth extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete MCP OAuth
|
||||
*
|
||||
* Complete OAuth authentication for a Model Context Protocol (MCP) server using the authorization code.
|
||||
* Complete OAuth authentication with authorization code
|
||||
*/
|
||||
public callback<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
@@ -1953,8 +1837,6 @@ export class Auth extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate MCP OAuth
|
||||
*
|
||||
* Start OAuth flow and wait for callback (opens browser)
|
||||
*/
|
||||
public authenticate<ThrowOnError extends boolean = false>(
|
||||
@@ -1985,8 +1867,6 @@ export class Auth extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set auth credentials
|
||||
*
|
||||
* Set authentication credentials
|
||||
*/
|
||||
public set<ThrowOnError extends boolean = false>(
|
||||
@@ -2024,9 +1904,7 @@ export class Auth extends HeyApiClient {
|
||||
|
||||
export class Mcp extends HeyApiClient {
|
||||
/**
|
||||
* Get MCP status
|
||||
*
|
||||
* Get the status of all Model Context Protocol (MCP) servers.
|
||||
* Get MCP server status
|
||||
*/
|
||||
public status<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -2043,9 +1921,7 @@ export class Mcp extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add MCP server
|
||||
*
|
||||
* Dynamically add a new Model Context Protocol (MCP) server to the system.
|
||||
* Add MCP server dynamically
|
||||
*/
|
||||
public add<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -2079,69 +1955,11 @@ export class Mcp extends HeyApiClient {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect an MCP server
|
||||
*/
|
||||
public connect<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
name: string
|
||||
directory?: string
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
const params = buildClientParams(
|
||||
[parameters],
|
||||
[
|
||||
{
|
||||
args: [
|
||||
{ in: "path", key: "name" },
|
||||
{ in: "query", key: "directory" },
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
return (options?.client ?? this.client).post<McpConnectResponses, unknown, ThrowOnError>({
|
||||
url: "/mcp/{name}/connect",
|
||||
...options,
|
||||
...params,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect an MCP server
|
||||
*/
|
||||
public disconnect<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
name: string
|
||||
directory?: string
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
const params = buildClientParams(
|
||||
[parameters],
|
||||
[
|
||||
{
|
||||
args: [
|
||||
{ in: "path", key: "name" },
|
||||
{ in: "query", key: "directory" },
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
return (options?.client ?? this.client).post<McpDisconnectResponses, unknown, ThrowOnError>({
|
||||
url: "/mcp/{name}/disconnect",
|
||||
...options,
|
||||
...params,
|
||||
})
|
||||
}
|
||||
|
||||
auth = new Auth({ client: this.client })
|
||||
}
|
||||
|
||||
export class Lsp extends HeyApiClient {
|
||||
/**
|
||||
* Get LSP status
|
||||
*
|
||||
* Get LSP server status
|
||||
*/
|
||||
public status<ThrowOnError extends boolean = false>(
|
||||
@@ -2161,8 +1979,6 @@ export class Lsp extends HeyApiClient {
|
||||
|
||||
export class Formatter extends HeyApiClient {
|
||||
/**
|
||||
* Get formatter status
|
||||
*
|
||||
* Get formatter status
|
||||
*/
|
||||
public status<ThrowOnError extends boolean = false>(
|
||||
@@ -2182,9 +1998,7 @@ export class Formatter extends HeyApiClient {
|
||||
|
||||
export class Control extends HeyApiClient {
|
||||
/**
|
||||
* Get next TUI request
|
||||
*
|
||||
* Retrieve the next TUI (Terminal User Interface) request from the queue for processing.
|
||||
* Get the next TUI request from the queue
|
||||
*/
|
||||
public next<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -2201,9 +2015,7 @@ export class Control extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit TUI response
|
||||
*
|
||||
* Submit a response to the TUI request queue to complete a pending request.
|
||||
* Submit a response to the TUI request queue
|
||||
*/
|
||||
public response<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -2228,8 +2040,6 @@ export class Control extends HeyApiClient {
|
||||
|
||||
export class Tui extends HeyApiClient {
|
||||
/**
|
||||
* Append TUI prompt
|
||||
*
|
||||
* Append prompt to the TUI
|
||||
*/
|
||||
public appendPrompt<ThrowOnError extends boolean = false>(
|
||||
@@ -2263,9 +2073,7 @@ export class Tui extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Open help dialog
|
||||
*
|
||||
* Open the help dialog in the TUI to display user assistance information.
|
||||
* Open the help dialog
|
||||
*/
|
||||
public openHelp<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
@@ -2282,8 +2090,6 @@ export class Tui extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Open sessions dialog
|
||||
*
|
||||
* Open the session dialog
|
||||
*/
|
||||
public openSessions<ThrowOnError extends boolean = false>(
|
||||
@@ -2301,8 +2107,6 @@ export class Tui extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Open themes dialog
|
||||
*
|
||||
* Open the theme dialog
|
||||
*/
|
||||
public openThemes<ThrowOnError extends boolean = false>(
|
||||
@@ -2320,8 +2124,6 @@ export class Tui extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Open models dialog
|
||||
*
|
||||
* Open the model dialog
|
||||
*/
|
||||
public openModels<ThrowOnError extends boolean = false>(
|
||||
@@ -2339,8 +2141,6 @@ export class Tui extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit TUI prompt
|
||||
*
|
||||
* Submit the prompt
|
||||
*/
|
||||
public submitPrompt<ThrowOnError extends boolean = false>(
|
||||
@@ -2358,8 +2158,6 @@ export class Tui extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear TUI prompt
|
||||
*
|
||||
* Clear the prompt
|
||||
*/
|
||||
public clearPrompt<ThrowOnError extends boolean = false>(
|
||||
@@ -2377,8 +2175,6 @@ export class Tui extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute TUI command
|
||||
*
|
||||
* Execute a TUI command (e.g. agent_cycle)
|
||||
*/
|
||||
public executeCommand<ThrowOnError extends boolean = false>(
|
||||
@@ -2412,8 +2208,6 @@ export class Tui extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Show TUI toast
|
||||
*
|
||||
* Show a toast notification in the TUI
|
||||
*/
|
||||
public showToast<ThrowOnError extends boolean = false>(
|
||||
@@ -2453,8 +2247,6 @@ export class Tui extends HeyApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish TUI event
|
||||
*
|
||||
* Publish a TUI event
|
||||
*/
|
||||
public publish<ThrowOnError extends boolean = false>(
|
||||
@@ -2482,8 +2274,6 @@ export class Tui extends HeyApiClient {
|
||||
|
||||
export class Event extends HeyApiClient {
|
||||
/**
|
||||
* Subscribe to events
|
||||
*
|
||||
* Get events
|
||||
*/
|
||||
public subscribe<ThrowOnError extends boolean = false>(
|
||||
|
||||
@@ -1708,7 +1708,7 @@ export type ProjectCurrentData = {
|
||||
|
||||
export type ProjectCurrentResponses = {
|
||||
/**
|
||||
* Current project information
|
||||
* Current project
|
||||
*/
|
||||
200: Project
|
||||
}
|
||||
@@ -3503,46 +3503,6 @@ export type McpAuthAuthenticateResponses = {
|
||||
|
||||
export type McpAuthAuthenticateResponse = McpAuthAuthenticateResponses[keyof McpAuthAuthenticateResponses]
|
||||
|
||||
export type McpConnectData = {
|
||||
body?: never
|
||||
path: {
|
||||
name: string
|
||||
}
|
||||
query?: {
|
||||
directory?: string
|
||||
}
|
||||
url: "/mcp/{name}/connect"
|
||||
}
|
||||
|
||||
export type McpConnectResponses = {
|
||||
/**
|
||||
* MCP server connected successfully
|
||||
*/
|
||||
200: boolean
|
||||
}
|
||||
|
||||
export type McpConnectResponse = McpConnectResponses[keyof McpConnectResponses]
|
||||
|
||||
export type McpDisconnectData = {
|
||||
body?: never
|
||||
path: {
|
||||
name: string
|
||||
}
|
||||
query?: {
|
||||
directory?: string
|
||||
}
|
||||
url: "/mcp/{name}/disconnect"
|
||||
}
|
||||
|
||||
export type McpDisconnectResponses = {
|
||||
/**
|
||||
* MCP server disconnected successfully
|
||||
*/
|
||||
200: boolean
|
||||
}
|
||||
|
||||
export type McpDisconnectResponse = McpDisconnectResponses[keyof McpDisconnectResponses]
|
||||
|
||||
export type LspStatusData = {
|
||||
body?: never
|
||||
path?: never
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "bun run src/index.ts",
|
||||
|
||||
@@ -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/index.ts" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@opencode-ai/tauri",
|
||||
"private": true,
|
||||
"version": "1.0.137",
|
||||
"version": "1.0.134",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"predev": "bun ./scripts/predev.ts",
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::{
|
||||
sync::{Arc, Mutex},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tauri::{AppHandle, Manager, RunEvent, WebviewUrl, WebviewWindow};
|
||||
use tauri::{App, AppHandle, Manager, RunEvent, WebviewUrl, WebviewWindow};
|
||||
use tauri_plugin_dialog::{DialogExt, MessageDialogButtons, MessageDialogResult};
|
||||
use tauri_plugin_shell::process::{CommandChild, CommandEvent};
|
||||
use tauri_plugin_shell::ShellExt;
|
||||
|
||||
1
packages/tauri/src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
import "@opencode-ai/desktop"
|
||||
@@ -1,21 +0,0 @@
|
||||
// @refresh reload
|
||||
import { render } from "solid-js/web"
|
||||
import { DesktopInterface, PlatformProvider, Platform } from "@opencode-ai/desktop"
|
||||
|
||||
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!,
|
||||
)
|
||||