Compare commits
721 Commits
v1.8.0
...
release/v0.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 16d5dd42cc | |||
| ab42d680cc | |||
| 8eb317e560 | |||
| d51ae7c239 | |||
| c0a2edf8bb | |||
| 5c8ea9fafa | |||
| 9351c239aa | |||
| dae36f6540 | |||
| b2dd04cff3 | |||
| 6da887754c | |||
| cb3e278695 | |||
| 65a860e75e | |||
| ac53dbb122 | |||
| fc5d0bdb5a | |||
| 142029b09f | |||
| 97b3764063 | |||
| d5fc9d7eb2 | |||
| 21eddabc58 | |||
| 07d3f3798c | |||
| b181007509 | |||
| 971489990c | |||
| e8c649a215 | |||
| f9bc6f3446 | |||
| bb967128b8 | |||
| 7380d77ef3 | |||
| 57a4f2be0e | |||
| e506f48da8 | |||
| a528a9e9e9 | |||
| 5d86ac412a | |||
| 32069f2882 | |||
| 98fd2c010c | |||
| 30d6b0e223 | |||
| 2521607a5e | |||
| 909bf7bdab | |||
| 045b469a7f | |||
| 413c4f8942 | |||
| c52866693c | |||
| 961c0f8707 | |||
| ebd6a5e342 | |||
| d90e44fc5a | |||
| 26c6a0105c | |||
| 742d169601 | |||
| 42ad58d128 | |||
| cb1fd31e36 | |||
| 56a7b53ed9 | |||
| f3344b8d2b | |||
| c1f188ff5b | |||
| cc360baf09 | |||
| 01837c1fb7 | |||
| 99c2f66990 | |||
| 5f3885c625 | |||
| 40e4d20f85 | |||
| d3d38fd227 | |||
| 353df9afd8 | |||
| 397e8bda1f | |||
| 572d2a1fcf | |||
| cf64c4e23f | |||
| 07a50a14c9 | |||
| 7752d34947 | |||
| 4f0e3a6f87 | |||
| a0e7bf60c2 | |||
| 54ef05f61b | |||
| bda1a0d4d6 | |||
| d3223f28d8 | |||
| 67ac1fd339 | |||
| 78c01b1c9b | |||
| a912a246fc | |||
| b4e96f13af | |||
| 3f58dde0a2 | |||
| 76ba587937 | |||
| ebd98c178d | |||
| 49978215db | |||
| e421775c94 | |||
| a87a62db54 | |||
| 8c256a6b41 | |||
| b1bcbfeadc | |||
| 66dd2e1de0 | |||
| 16fbfe1376 | |||
| f915fb2e2d | |||
| c5763167ee | |||
| 2dceadbb24 | |||
| c9d274fd84 | |||
| c9b37326bd | |||
| c497eb1ff2 | |||
| 542c246a55 | |||
| 4ba3cc87a2 | |||
| 1e04e5c37a | |||
| c204ad711b | |||
| 2e95f29572 | |||
| 7191b0ac92 | |||
| c12343f07b | |||
| f40826c1eb | |||
| f4d655dfda | |||
| e5fe26c808 | |||
| ac428ef0be | |||
| c40ba64230 | |||
| 838f6c24fe | |||
| c8514500bd | |||
| 977d81dc3b | |||
| 365daa9c6d | |||
| 5bbae7e9cc | |||
| a3b3533377 | |||
| 084f6ede62 | |||
| 1bc61fe1fd | |||
| f0b04d2acf | |||
| fa5b8616cf | |||
| 4f7cd7fb20 | |||
| e8369ad576 | |||
| cec2695721 | |||
| b1efd356f5 | |||
| c3c6fc63be | |||
| 681fd1d0e6 | |||
| f1650d11da | |||
| c530c9d6e5 | |||
| c0733e6daa | |||
| 00297499a0 | |||
| 884e56f0e5 | |||
| edda72110e | |||
| 1fe1fd9446 | |||
| 99cc41c328 | |||
| 5f97b4b7fa | |||
| d5cab33bc2 | |||
| f193683de6 | |||
| 960e071b88 | |||
| 5c58a9be75 | |||
| 7deb753165 | |||
| b5f9c30eb0 | |||
| 36aaa18291 | |||
| 561f688e2a | |||
| a5bfd74c6d | |||
| 73334cbe8d | |||
| cc42f2f81c | |||
| c454a3bf4b | |||
| e97befbb36 | |||
| 26ee05dd07 | |||
| 29725445cc | |||
| 0c7b12a2c0 | |||
| a655c55278 | |||
| a0690ee4ca | |||
| f1db87c498 | |||
| cdfba1e402 | |||
| 7e3a770a4c | |||
| 36486e12ee | |||
| 991175d72e | |||
| b263b6adba | |||
| a88d45d8b4 | |||
| d9af2acf5b | |||
| f4df887fcd | |||
| 4922201c41 | |||
| f6f0fc8b1d | |||
| a728c8cead | |||
| 3f35aabbf9 | |||
| e643a4fbd4 | |||
| 10515035fe | |||
| 4f196f4a0e | |||
| 93e4f1cc6c | |||
| d25fa0b14e | |||
| 1627f41215 | |||
| 6ceda01b24 | |||
| f1a9f3fed7 | |||
| 1d7884d062 | |||
| 87772db80d | |||
| df31f6bfeb | |||
| a88504e4fe | |||
| dca42c4891 | |||
| 44a331f6c1 | |||
| 6bde6c6cbf | |||
| 39b0389b9d | |||
| 806fe70c51 | |||
| d9ea1e606c | |||
| 88af56c06c | |||
| 86f3dc2fb5 | |||
| ef5bd56599 | |||
| fed40d5963 | |||
| 05f85ecfeb | |||
| e72d9912b2 | |||
| c50af7226c | |||
| 2b32940ca2 | |||
| fc82e95beb | |||
| 89b9b56b74 | |||
| d9e1031f85 | |||
| 8ec0b2cf08 | |||
| 8d7b70b1e5 | |||
| c7c6c8f0d6 | |||
| 771332ca3e | |||
| 77b722c077 | |||
| d6e308d679 | |||
| 21ae763f13 | |||
| 7e32e772cb | |||
| 7aeab15ecf | |||
| 43bf383784 | |||
| f4ae4c66df | |||
| 1b0863d336 | |||
| d22c6c5540 | |||
| 7b894f100f | |||
| ab8f5d6f36 | |||
| 96005f0ad9 | |||
| 7ed03022f5 | |||
| 1d97429e28 | |||
| d0cdabe0ca | |||
| 8cfc0fa4f4 | |||
| 5e1581fab3 | |||
| 3109fdb0f4 | |||
| bbee587cfe | |||
| 52bb98fd90 | |||
| 2b1e3f553b | |||
| 06146d5bd0 | |||
| ed17085df9 | |||
| 33e04c8baa | |||
| 6302ae0eb2 | |||
| 0bcfe0275e | |||
| 699ae18a7f | |||
| 67786ada49 | |||
| e35d69d124 | |||
| 52582c44b1 | |||
| 7d1830f90b | |||
| ee9c865cd4 | |||
| 51e218c81a | |||
| ce2610a6ea | |||
| 71f4e85cea | |||
| 477d7d995d | |||
| a025b5cfd3 | |||
| 0f0930726c | |||
| 178c15f47d | |||
| 4bf69b894d | |||
| 6764a5cdec | |||
| 3eca52e76d | |||
| e7a180e368 | |||
| a79520d496 | |||
| af5ae9a5f0 | |||
| 4ba68df1ee | |||
| c4a9e50610 | |||
| 9e7756ce0f | |||
| 2e9e633cdc | |||
| e0b90b2ea5 | |||
| 1f2acc519b | |||
| f6c19c29a6 | |||
| 9720d0c610 | |||
| cf6fd27977 | |||
| d542d751d7 | |||
| 5c0aeb9671 | |||
| 928ea39fae | |||
| 69d20aa29f | |||
| 5d19724c06 | |||
| 5672e6c825 | |||
| 25cd7cc8e2 | |||
| 9de7253998 | |||
| a7e9d47375 | |||
| 5141bd9e6c | |||
| 781434dd97 | |||
| 2f7c4a1c92 | |||
| 20effe4a89 | |||
| 69311f013c | |||
| 66aaf646be | |||
| 8449550e80 | |||
| f4590ce50f | |||
| fcc5c8f4ba | |||
| 505e7ea481 | |||
| 11450e17ab | |||
| 9ab24806f9 | |||
| 576de4df1a | |||
| caecfc0066 | |||
| b5e48e04ff | |||
| 7c142410f2 | |||
| f770487695 | |||
| f4b0887f60 | |||
| c0cea6d591 | |||
| 1dc9cfa1b0 | |||
| d67832f5f3 | |||
| f873a51521 | |||
| 35b9e4c85c | |||
| 7386e3db2b | |||
| ed99fb0a42 | |||
| e08cff2fa8 | |||
| b2cae6c2fb | |||
| 2c0340eaaa | |||
| 164d5eac7b | |||
| 2b5ffa1493 | |||
| 5b1c68337d | |||
| 2c5eecda95 | |||
| f87b70f5ba | |||
| 2a9150de66 | |||
| daaeabdf26 | |||
| a1280a59ab | |||
| a3b29251f9 | |||
| 9822ee79b6 | |||
| d6b4d206d8 | |||
| ed32da7833 | |||
| 0ce66acd44 | |||
| 713ed3f959 | |||
| 68df88e808 | |||
| 2f9c28ec99 | |||
| f5e755eae4 | |||
| aedb21d193 | |||
| 897de134f7 | |||
| 06dab2c3df | |||
| d8080d7209 | |||
| 6ef15cfdfb | |||
| c94ee5ed74 | |||
| d7db93ead1 | |||
| bfed826033 | |||
| 8974a9ce69 | |||
| 860d315d7d | |||
| abb0e37e88 | |||
| c99e8e8cb7 | |||
| 031da29a57 | |||
| 75e3b9116d | |||
| ffca24301a | |||
| 2798814871 | |||
| 55a359d351 | |||
| b932531911 | |||
| 8a7ba91ac1 | |||
| bbb753761f | |||
| 129bd124dd | |||
| 2e5b7eb57c | |||
| 4988a71524 | |||
| 6e77c28716 | |||
| 9b68ca2226 | |||
| 114850e83b | |||
| 87d54df4ec | |||
| 095920c4e1 | |||
| d2c85760fb | |||
| ead5fe9625 | |||
| 9176bf74b1 | |||
| b7b5d28bb1 | |||
| 5900629e6a | |||
| 7fa399c6af | |||
| 6b1a48f2fb | |||
| 4530e8f9e3 | |||
| eca8cc61ac | |||
| d577ec4ba1 | |||
| 133bd6e38f | |||
| 1c9f65ab7c | |||
| 63273312b2 | |||
| e58a722416 | |||
| 1f4d688d94 | |||
| 67f53899f9 | |||
| ebb603feb8 | |||
| 0045126054 | |||
| 93af89dbf9 | |||
| d480015b16 | |||
| eccaa8360c | |||
| 1511e0522e | |||
| f406147a30 | |||
| cd54c501b4 | |||
| fdcf514d61 | |||
| 3ee34f7422 | |||
| 219550c515 | |||
| c3d12c5663 | |||
| f468968b44 | |||
| 44f70c1102 | |||
| d49397bdb2 | |||
| e07e7e06a1 | |||
| 635aa12957 | |||
| 0f36197230 | |||
| f2f44c9ad1 | |||
| 59bcb74322 | |||
| 37d940b137 | |||
| c1b1d87869 | |||
| 88cb60efe1 | |||
| 69533ad112 | |||
| 2dd0590f8a | |||
| a34f39452c | |||
| 657881dbe2 | |||
| afd2dd3eea | |||
| d0f4e9126f | |||
| e52c5f7dce | |||
| 66ac67839c | |||
| f5ace866e8 | |||
| d05033909b | |||
| cb55360738 | |||
| 18d13ac66b | |||
| dc2a9682f8 | |||
| 8001322ff2 | |||
| 1319105bb4 | |||
| 61311e3f41 | |||
| 7056f6c689 | |||
| 6a83736d30 | |||
| 6c5db4135e | |||
| ede6a40405 | |||
| 1492604ee6 | |||
| 17d481d4d1 | |||
| fa62548b01 | |||
| bee3df5319 | |||
| 5052944efe | |||
| b5d03dd523 | |||
| 93e70c62f1 | |||
| 8d7e28c5e3 | |||
| 0d256239f3 | |||
| 39bc35eec1 | |||
| bac0b1a0cb | |||
| ff725d35ff | |||
| 6a63c9f11b | |||
| ad29ff2a03 | |||
| 2eb11aadc7 | |||
| e0f92d2985 | |||
| d06b85b9fc | |||
| d1a43fa43e | |||
| 69ba0c833e | |||
| c54c6d82f5 | |||
| 48cdfa9874 | |||
| ac66cb89c0 | |||
| 3c6a550ecf | |||
| d8d5fcca37 | |||
| efacc1a83a | |||
| 5adf96dc82 | |||
| 4658e5cead | |||
| 87d10c36d1 | |||
| 594e73ec4e | |||
| 5f0067c915 | |||
| a4aed4756a | |||
| 20e68748aa | |||
| b981b3a552 | |||
| d48d4378ed | |||
| bca22a8aa1 | |||
| 4ae190f70e | |||
| cf2ec27a44 | |||
| 78a3666f68 | |||
| fbc987e220 | |||
| c65217ee7e | |||
| 3ba1eaf908 | |||
| 978c6996af | |||
| b05cc0d059 | |||
| 04b483a67f | |||
| 68df8809ad | |||
| d9f9e7ba16 | |||
| 17f34e6225 | |||
| 0fb9796d8b | |||
| e9c485ab5a | |||
| fbd3a64123 | |||
| e5266ddda1 | |||
| 62688c261a | |||
| 165272ab47 | |||
| 52f86b1887 | |||
| a803dd15ae | |||
| d38ee345d2 | |||
| 9052528d2b | |||
| cbf942e700 | |||
| 60b5a540de | |||
| 70d30e9f2b | |||
| 364f0921ba | |||
| 717d83b5cb | |||
| 0d09897aa6 | |||
| e554cf7ae7 | |||
| b33abaa8b5 | |||
| 15b105b6c9 | |||
| fa32dcc1c8 | |||
| 24292759b3 | |||
| c38e079aa6 | |||
| cc32912a72 | |||
| 68e29bab66 | |||
| 5c37c98542 | |||
| c05f51fc4e | |||
| 4278ac0cd0 | |||
| 90b0c8243c | |||
| fb5a8ea524 | |||
| d3d7ea44d0 | |||
| 82229faffe | |||
| 5a94f6434b | |||
| dff81b9d09 | |||
| 3761023b60 | |||
| ef0157bbce | |||
| 3e3f7113f3 | |||
| a57fb8e436 | |||
| cd994eb87e | |||
| 0b3b23320b | |||
| d9af8b0948 | |||
| e3ad10d511 | |||
| 2b97775c96 | |||
| b7027464f9 | |||
| 04f4494ca0 | |||
| d422afda8f | |||
| cc4825efc3 | |||
| fe1f2a793a | |||
| df82c8bdbb | |||
| cb47d2efc4 | |||
| 86437940fa | |||
| 19598f3704 | |||
| 0c9ebb2d28 | |||
| b0c9e8db31 | |||
| 11bf0ecccc | |||
| 799e5ca180 | |||
| bb4bedcb66 | |||
| 1169dd6c2b | |||
| 126a43164b | |||
| bf05131b81 | |||
| 26bcc0b7ca | |||
| f8b76256f3 | |||
| cc96efc271 | |||
| 540f5326b7 | |||
| dfeb2ee3e3 | |||
| 73acab8bbe | |||
| 817584d8b5 | |||
| 8db3634c17 | |||
| 554c4004d3 | |||
| 88908cfbbf | |||
| dfec4772e9 | |||
| a4de927696 | |||
| 71de5db36a | |||
| d9e360fa05 | |||
| ccb4738d7e | |||
| 729e32514e | |||
| e6d6ca5c56 | |||
| da505170d4 | |||
| 4ea6d17997 | |||
| 368ec5e042 | |||
| 8aa11bd8fe | |||
| 3a4c98d0bf | |||
| 946605f990 | |||
| 1ac3275341 | |||
| 519c6bb249 | |||
| 5d58a08e6c | |||
| 739a7e070e | |||
| 1ddd70238f | |||
| bc8304521e | |||
| 957fe4ad02 | |||
| 8f4a65bc79 | |||
| d0bf4f3711 | |||
| 5bd754e9f3 | |||
| 31f5fabc54 | |||
| 5190d30ae3 | |||
| c04dfc76cb | |||
| 09001fa72a | |||
| 7612e50a5f | |||
| 0932361c7d | |||
| d5a998a23a | |||
| 7ee0a58f9b | |||
| 05eab1f22f | |||
| 34f160b35a | |||
| 372c4df3bf | |||
| d67523596b | |||
| 7dd9abda46 | |||
| 6502b3cb24 | |||
| 385c54d3c0 | |||
| 83ce17db11 | |||
| 23d664be8e | |||
| 0914c069af | |||
| 5d1e13854e | |||
| d235c2d1c5 | |||
| fe052d28df | |||
| da3aa7a658 | |||
| f0315c1520 | |||
| 2176669cb5 | |||
| 6c03fdfbb9 | |||
| 636e6927f7 | |||
| 4f51316f76 | |||
| 874d667ff4 | |||
| 9338f2a45f | |||
| 16fdaff8b3 | |||
| 4f803c70cb | |||
| 5d9b0d26d0 | |||
| e9a169f19e | |||
| 6682321b6b | |||
| 1c5dca9346 | |||
| 99f4e06024 | |||
| 289ccfe0e5 | |||
| ba6546e0b8 | |||
| c920f4e2ed | |||
| 472fb1d234 | |||
| b7a5a3c952 | |||
| 46868d3140 | |||
| ca441c4bd6 | |||
| 27abea6ca5 | |||
| 7b4ad310ad | |||
| 114c850e4e | |||
| 766ead99dd | |||
| 61068fb387 | |||
| 3ea474795a | |||
| ab3d987f0c | |||
| afa9699ec8 | |||
| c908b78e1b | |||
| d9ffff7cec | |||
| 916dceafab | |||
| c79afa52cc | |||
| e37fa7cff9 | |||
| fbd30281bc | |||
| 4573010e16 | |||
| ecff59004d | |||
| cfefd1b798 | |||
| f6a14fdfb9 | |||
| 9ffe01888a | |||
| 7cb0c524e5 | |||
| d5b3bd7788 | |||
| 27d0452460 | |||
| e50edd0767 | |||
| 237c9aa02f | |||
| c687086b69 | |||
| f7fac83110 | |||
| d6f8c973e3 | |||
| 79e23c998c | |||
| 8d70c37f2a | |||
| 1a5e9759d8 | |||
| 0c290b4108 | |||
| e1ab10f24e | |||
| 6aa726fc8d | |||
| 05920b5233 | |||
| 25ce9d2238 | |||
| d3ba8357ec | |||
| 77e0738d4c | |||
| bb18993845 | |||
| 0dc0d95b63 | |||
| a911b5d8a2 | |||
| ed9fea780f | |||
| 905ec5ea50 | |||
| f3fe7c9f5a | |||
| 2f08aed301 | |||
| 3397920cb9 | |||
| 2de5971adc | |||
| 6b5f33c7e8 | |||
| 99108eaa50 | |||
| f872911de2 | |||
| c664403d4e | |||
| 5fa3794610 | |||
| 42bcc4420d | |||
| 9b1b9c10a1 | |||
| c2a2e1b54c | |||
| 20c1984fb0 | |||
| 8b243fa536 | |||
| 2ed84244d5 | |||
| 204116c6d3 | |||
| 156f735c89 | |||
| ab327e3bbf | |||
| 9e01aaa3d3 | |||
| 2b63b91bfb | |||
| ebead1b1fa | |||
| 06ccaf6f67 | |||
| 59c188019a | |||
| 7271152f62 | |||
| 19a0ac00bd | |||
| c481e5da88 | |||
| b4a540a269 | |||
| 6c702d86ee | |||
| c1f3185e00 | |||
| 1f838bcb1d | |||
| 912ae07cbc | |||
| 103f82145e | |||
| 68b87e6056 | |||
| 36ba28d347 | |||
| b1dcff8f64 | |||
| 3b7af5749d | |||
| ec2b9c847e | |||
| 85e3042794 | |||
| 44a9e8055b | |||
| 1cc3546b7e | |||
| e5e890d2eb | |||
| 361edd47fa | |||
| 62cd1a74cb | |||
| 1d4f82b383 | |||
| 1cb426f7f8 | |||
| 1a847cd33f | |||
| 5a127c8b45 | |||
| 5dafd86650 | |||
| bb6a3a1a3f | |||
| 5069e1a11b | |||
| fb092289f2 | |||
| b347acf4f0 | |||
| 8b69e2a8b5 | |||
| c2aff91973 | |||
| d81002decc | |||
| a82ff941b9 | |||
| ae1c06b711 | |||
| 05389b7dd5 | |||
| 7a2f1baef9 | |||
| 6fe9ed22b0 | |||
| 40f7942801 | |||
| 7c21a4c833 | |||
| dedf8e9e48 | |||
| 98441bf98c | |||
| 888b3b7022 | |||
| 24bad56785 | |||
| e410e317cc | |||
| 4a1f61d4b5 | |||
| 4e10e1ec3d | |||
| 3466859536 | |||
| a009c84597 | |||
| f774e62c13 | |||
| 1ab7d55ef7 | |||
| 445f0f6d7a | |||
| aa9b63e4ca | |||
| 002ae0ded5 | |||
| 3f2e107c53 | |||
| 973c1cd604 | |||
| 92a1bcca93 | |||
| d6149bd2ef | |||
| af64942f9f | |||
| d29ba68fa0 | |||
| 27e52ed7e8 | |||
| e587345ba7 | |||
| 6e69ea90df | |||
| 89cead483c | |||
| ef95f6763a | |||
| 02a294345f | |||
| 81a18d21a9 | |||
| fb24a2a796 | |||
| ae770a1c6a | |||
| fd2472de3b | |||
| b5ca470ebf | |||
| 69e681ebce | |||
| 1602ecfe67 | |||
| 9965c33ef7 | |||
| d4f15de199 | |||
| 3bd09e4e1b | |||
| 1528aeb3dd | |||
| 47d5902ef9 | |||
| 46ceafa016 | |||
| 2e272a1ad3 | |||
| 99a82e5563 | |||
| e1d38edda5 | |||
| d563abd233 | |||
| aea79f8450 | |||
| eccf8000d3 | |||
| f1f82470a0 | |||
| 2e865f32fe | |||
| a690fb28fe | |||
| f7d12a3e02 | |||
| f282df604a | |||
| 25831b5752 | |||
| 3a30f69e0d | |||
| abb4a0143e | |||
| 4d1db22fe3 | |||
| f001aad306 |
@@ -0,0 +1,6 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
|
||||
and is generated by [Changie](https://github.com/miniscruff/changie).
|
||||
@@ -0,0 +1,3 @@
|
||||
## v0.1.0 - 2025-01-29
|
||||
### Added
|
||||
* new section to README about Changie
|
||||
@@ -0,0 +1,26 @@
|
||||
changesDir: .changes
|
||||
unreleasedDir: unreleased
|
||||
headerPath: header.tpl.md
|
||||
changelogPath: CHANGELOG.md
|
||||
versionExt: md
|
||||
versionFormat: '## {{.Version}} - {{.Time.Format "2006-01-02"}}'
|
||||
kindFormat: "### {{.Kind}}"
|
||||
changeFormat: "* {{.Body}}"
|
||||
kinds:
|
||||
- label: Added
|
||||
auto: minor
|
||||
- label: Changed
|
||||
auto: major
|
||||
- label: Deprecated
|
||||
auto: minor
|
||||
- label: Removed
|
||||
auto: major
|
||||
- label: Fixed
|
||||
auto: patch
|
||||
- label: Security
|
||||
auto: patch
|
||||
newlines:
|
||||
afterChangelogHeader: 1
|
||||
beforeChangelogVersion: 1
|
||||
endOfVersion: 1
|
||||
envPrefix: CHANGIE_
|
||||
@@ -1,31 +1,25 @@
|
||||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/naming-convention": [
|
||||
"warn",
|
||||
{
|
||||
"selector": "import",
|
||||
"format": [ "camelCase", "PascalCase" ]
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/semi": "off",
|
||||
"curly": "warn",
|
||||
"eqeqeq": "warn",
|
||||
"no-throw-literal": "warn",
|
||||
"semi": "off",
|
||||
"react-hooks/exhaustive-deps": "off"
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"out",
|
||||
"dist",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"rules": {
|
||||
"@typescript-eslint/naming-convention": [
|
||||
"warn",
|
||||
{
|
||||
"selector": "import",
|
||||
"format": ["camelCase", "PascalCase"]
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/semi": "off",
|
||||
"curly": "warn",
|
||||
"eqeqeq": "warn",
|
||||
"no-throw-literal": "warn",
|
||||
"semi": "off",
|
||||
"react-hooks/exhaustive-deps": "off"
|
||||
},
|
||||
"ignorePatterns": ["out", "dist", "**/*.d.ts"]
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
demo.gif filter=lfs diff=lfs merge=lfs -text
|
||||
assets/docs/demo.gif filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
* @saoudrizwan @ocasta181 @NightTrek @pashpashpash
|
||||
@@ -0,0 +1,54 @@
|
||||
name: 🐛 Bug Report
|
||||
description: File a bug report
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**Important:** All bug reports must be reproducible using Claude 3.5 Sonnet. Cline uses complex prompts so less capable models may not work as expected.
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen?
|
||||
placeholder: Tell us what you see!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: How do you trigger this bug? Please walk us through it step by step.
|
||||
value: |
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant API REQUEST output
|
||||
description: Please copy and paste any relevant output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
- type: input
|
||||
id: operating-system
|
||||
attributes:
|
||||
label: Operating System
|
||||
description: What operating system are you using?
|
||||
placeholder: "e.g., Windows 11, macOS Sonoma, Ubuntu 22.04"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: cline-version
|
||||
attributes:
|
||||
label: Cline Version
|
||||
description: What version of Cline are you using? (You can find this at the bottom of the Settings view)
|
||||
placeholder: "e.g., 1.2.3"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here, such as screenshots or related issues.
|
||||
@@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: ✨ Feature Request
|
||||
url: https://github.com/cline/cline/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop
|
||||
about: Share and vote on feature requests for Cline
|
||||
- name: 👋 Cline Discord
|
||||
url: https://discord.gg/cline
|
||||
about: Join our Discord community for discussions and support
|
||||
- name: ❓ Other Questions?
|
||||
url: https://x.com/sdrzn
|
||||
about: Contact the developer on X @sdrzn for other inquiries
|
||||
@@ -0,0 +1,39 @@
|
||||
version: 2
|
||||
updates:
|
||||
# Main extension dependencies
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
# Group all updates into a single PR
|
||||
groups:
|
||||
all-dependencies:
|
||||
patterns:
|
||||
- "*"
|
||||
ignore:
|
||||
# Ignore all non-security updates (security vulnerabilities bypass these ignore rules)
|
||||
- dependency-name: "*"
|
||||
update-types:
|
||||
- "version-update:semver-major"
|
||||
- "version-update:semver-minor"
|
||||
- "version-update:semver-patch"
|
||||
|
||||
# Webview UI dependencies
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/webview-ui"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
groups:
|
||||
all-dependencies:
|
||||
patterns:
|
||||
- "*"
|
||||
ignore:
|
||||
# Ignore CRA and related packages that often have false positives
|
||||
- dependency-name: "react-scripts"
|
||||
- dependency-name: "@testing-library/*"
|
||||
- dependency-name: "web-vitals"
|
||||
- dependency-name: "*"
|
||||
update-types:
|
||||
- "version-update:semver-major"
|
||||
- "version-update:semver-minor"
|
||||
- "version-update:semver-patch"
|
||||
@@ -0,0 +1,32 @@
|
||||
### Description
|
||||
|
||||
<!-- Describe your changes in detail. What problem does this PR solve? -->
|
||||
|
||||
### Test Procedure
|
||||
|
||||
<!-- How did you test this? Are you confident that it will not introduce bugs? If so, why? -->
|
||||
|
||||
### Type of Change
|
||||
|
||||
<!-- Put an 'x' in all boxes that apply -->
|
||||
|
||||
- [ ] 🐛 Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] ✨ New feature (non-breaking change which adds functionality)
|
||||
- [ ] 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] 📚 Documentation update
|
||||
|
||||
### Pre-flight Checklist
|
||||
|
||||
<!-- Put an 'x' in all boxes that apply -->
|
||||
|
||||
- [ ] Changes are limited to a single feature, bugfix or chore (split larger changes into separate PRs)
|
||||
- [ ] Tests are passing (`npm test`) and code is formatted and linted (`npm run format && npm run lint`)
|
||||
- [ ] I have reviewed [contributor guidelines](https://github.com/cline/cline/blob/main/CONTRIBUTING.md)
|
||||
|
||||
### Screenshots
|
||||
|
||||
<!-- For UI changes, add screenshots here -->
|
||||
|
||||
### Additional Notes
|
||||
|
||||
<!-- Add any additional notes for reviewers -->
|
||||
@@ -0,0 +1,82 @@
|
||||
name: "Changie Version PR"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
version-pr:
|
||||
name: Create/Update Version PR
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Important for changelog history
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.15.1
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
# Validate that changes exist
|
||||
- name: Check for Changie entries
|
||||
run: |
|
||||
if [ -z "$(find .changes/unreleased -name "*.yaml" -o -name "*.yml" 2>/dev/null)" ]; then
|
||||
echo "Error: No Changie entries found in .changes/unreleased/"
|
||||
echo "Please run 'npm run changie new' and commit the generated change file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Use Changie to batch changes and get the next version
|
||||
- name: Batch changes
|
||||
id: batch
|
||||
uses: miniscruff/changie-action@v2
|
||||
with:
|
||||
args: batch auto
|
||||
|
||||
# If no changes, stop here
|
||||
- name: Check for changes
|
||||
id: check
|
||||
run: |
|
||||
if [ -z "$(git status --porcelain)" ]; then
|
||||
echo "No changes to process"
|
||||
echo "has_changes=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "has_changes=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
# If we have changes, merge them and create/update PR
|
||||
- name: Merge changes
|
||||
if: steps.check.outputs.has_changes == 'true'
|
||||
uses: miniscruff/changie-action@v2
|
||||
with:
|
||||
args: merge
|
||||
|
||||
- name: Get latest version
|
||||
if: steps.check.outputs.has_changes == 'true'
|
||||
id: latest
|
||||
uses: miniscruff/changie-action@v2
|
||||
with:
|
||||
args: latest
|
||||
|
||||
- name: Create Pull Request
|
||||
if: steps.check.outputs.has_changes == 'true'
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
title: "Release ${{ steps.latest.outputs.output }}"
|
||||
branch: "release/${{ steps.latest.outputs.output }}"
|
||||
commit-message: "chore: update changelog for ${{ steps.latest.outputs.output }}"
|
||||
branch-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
body: |
|
||||
This PR was automatically created by the Changie workflow.
|
||||
- Updates CHANGELOG.md
|
||||
- Bumps version to ${{ steps.latest.outputs.output }}
|
||||
@@ -0,0 +1,108 @@
|
||||
name: "Publish Release"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release-type:
|
||||
description: "Choose release type (release or pre-release)"
|
||||
required: true
|
||||
default: "release"
|
||||
type: choice
|
||||
options:
|
||||
- pre-release
|
||||
- release
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
test:
|
||||
uses: ./.github/workflows/test.yml
|
||||
|
||||
publish:
|
||||
needs: test
|
||||
name: Publish Extension
|
||||
runs-on: ubuntu-latest
|
||||
environment: publish
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.15.1
|
||||
|
||||
# Cache root dependencies - only reuse if package-lock.json exactly matches
|
||||
- name: Cache root dependencies
|
||||
uses: actions/cache@v4
|
||||
id: root-cache
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
|
||||
|
||||
# Cache webview-ui dependencies - only reuse if package-lock.json exactly matches
|
||||
- name: Cache webview-ui dependencies
|
||||
uses: actions/cache@v4
|
||||
id: webview-cache
|
||||
with:
|
||||
path: webview-ui/node_modules
|
||||
key: ${{ runner.os }}-npm-webview-${{ hashFiles('webview-ui/package-lock.json') }}
|
||||
|
||||
- name: Install root dependencies
|
||||
if: steps.root-cache.outputs.cache-hit != 'true'
|
||||
run: npm ci
|
||||
|
||||
- name: Install webview-ui dependencies
|
||||
if: steps.webview-cache.outputs.cache-hit != 'true'
|
||||
run: cd webview-ui && npm ci
|
||||
|
||||
- name: Install Publishing Tools
|
||||
run: npm install -g vsce ovsx
|
||||
|
||||
- name: Get Version
|
||||
id: get_version
|
||||
run: echo "version=$(node -p \"require('./package.json').version\")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create Git Tag
|
||||
run: |
|
||||
VERSION=v${{ steps.get_version.outputs.version }}
|
||||
echo "Tagging with $VERSION"
|
||||
git tag "$VERSION"
|
||||
git push origin "$VERSION"
|
||||
|
||||
- name: Package and Publish Extension
|
||||
env:
|
||||
VSCE_PAT: ${{ secrets.VSCE_PAT }}
|
||||
OVSX_PAT: ${{ secrets.OVSX_PAT }}
|
||||
run: |
|
||||
# Required to generate the .vsix
|
||||
vsce package --out "cline-${{ steps.get_version.outputs.version }}.vsix"
|
||||
|
||||
if [ "${{ github.event.inputs.release-type }}" = "pre-release" ]; then
|
||||
npm run publish:marketplace:prerelease
|
||||
echo "Successfully published pre-release version ${{ steps.get_version.outputs.version }} to VS Code Marketplace and Open VSX Registry"
|
||||
else
|
||||
npm run publish:marketplace
|
||||
echo "Successfully published release version ${{ steps.get_version.outputs.version }} to VS Code Marketplace and Open VSX Registry"
|
||||
fi
|
||||
|
||||
- name: Get Changelog Entry
|
||||
id: changelog
|
||||
uses: mindsers/changelog-reader-action@v2
|
||||
with:
|
||||
# This expects a standard Keep a Changelog format
|
||||
# "latest" means it will read whichever is the most recent version
|
||||
# set in "## [1.2.3] - 2025-01-28" style
|
||||
version: latest
|
||||
|
||||
- name: Create GitHub Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: "*.vsix"
|
||||
body: ${{ steps.changelog.outputs.content }}
|
||||
generate_release_notes: false
|
||||
prerelease: ${{ github.event.inputs.release-type == 'pre-release' }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,61 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
# Set default permissions for all jobs
|
||||
permissions:
|
||||
contents: read # Needed to check out code
|
||||
checks: write # Needed to report test results
|
||||
pull-requests: write # Needed to add comments/annotations to PRs
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js environment
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.15.1
|
||||
|
||||
# Cache root dependencies - only reuse if package-lock.json exactly matches
|
||||
- name: Cache root dependencies
|
||||
uses: actions/cache@v4
|
||||
id: root-cache
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
|
||||
|
||||
# Cache webview-ui dependencies - only reuse if package-lock.json exactly matches
|
||||
- name: Cache webview-ui dependencies
|
||||
uses: actions/cache@v4
|
||||
id: webview-cache
|
||||
with:
|
||||
path: webview-ui/node_modules
|
||||
key: ${{ runner.os }}-npm-webview-${{ hashFiles('webview-ui/package-lock.json') }}
|
||||
|
||||
- name: Install root dependencies
|
||||
if: steps.root-cache.outputs.cache-hit != 'true'
|
||||
run: npm ci
|
||||
|
||||
- name: Install webview-ui dependencies
|
||||
if: steps.webview-cache.outputs.cache-hit != 'true'
|
||||
run: cd webview-ui && npm ci
|
||||
|
||||
- name: Type Check
|
||||
run: npm run check-types
|
||||
|
||||
- name: ESLint Check
|
||||
run: npm run lint
|
||||
|
||||
- name: Prettier / Format Check
|
||||
run: npm run format
|
||||
|
||||
- name: Extension Tests
|
||||
run: xvfb-run -a npm run test
|
||||
@@ -1,5 +1,10 @@
|
||||
out
|
||||
dist
|
||||
node_modules
|
||||
tmp
|
||||
.vscode-test/
|
||||
*.vsix
|
||||
|
||||
.DS_Store
|
||||
|
||||
pnpm-lock.yaml
|
||||
@@ -0,0 +1,17 @@
|
||||
echo "Running pre-commit checks..."
|
||||
|
||||
# Run ESLint
|
||||
echo "Running ESLint..."
|
||||
npm run lint || {
|
||||
echo "❌ ESLint check failed. Please fix the errors and try committing again."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Run Prettier
|
||||
echo "Running Prettier..."
|
||||
npm run format || {
|
||||
echo "❌ Prettier check failed. Run 'npm run format:fix' to automatically fix formatting issues."
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "✅ All checks passed!"
|
||||
@@ -1,4 +1,5 @@
|
||||
dist/
|
||||
node_modules
|
||||
webview-ui/build/
|
||||
CHANGELOG.md
|
||||
*.md
|
||||
package-lock.json
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"tabWidth": 4,
|
||||
"useTabs": true,
|
||||
"printWidth": 120,
|
||||
"printWidth": 130,
|
||||
"semi": false,
|
||||
"jsxBracketSameLine": true
|
||||
}
|
||||
"bracketSameLine": true
|
||||
}
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
import { defineConfig } from '@vscode/test-cli';
|
||||
import { defineConfig } from "@vscode/test-cli"
|
||||
import path from "path"
|
||||
|
||||
export default defineConfig({
|
||||
files: 'out/test/**/*.test.js',
|
||||
});
|
||||
files: "{out/test/**/*.test.js,src/test/suite/**/*.test.js}",
|
||||
mocha: {
|
||||
ui: "bdd",
|
||||
timeout: 20000, // Maximum time (in ms) that a test can run before failing
|
||||
},
|
||||
workspaceFolder: "test-workspace",
|
||||
version: "stable",
|
||||
extensionDevelopmentPath: path.resolve("./"),
|
||||
launchArgs: ["--disable-extensions"],
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": ["dbaeumer.vscode-eslint", "connor4312.esbuild-problem-matchers", "ms-vscode.extension-test-runner"]
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": ["dbaeumer.vscode-eslint", "connor4312.esbuild-problem-matchers", "ms-vscode.extension-test-runner"]
|
||||
}
|
||||
|
||||
@@ -9,12 +9,8 @@
|
||||
"name": "Run Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/**/*.js"
|
||||
],
|
||||
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
|
||||
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
|
||||
"preLaunchTask": "${defaultBuildTask}"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
"files.exclude": {
|
||||
"out": false, // set this to true to hide the "out" folder with the compiled JS files
|
||||
"dist": false // set this to true to hide the "dist" folder with the compiled JS files
|
||||
},
|
||||
"search.exclude": {
|
||||
"out": true, // set this to false to include "out" folder in search results
|
||||
"dist": true // set this to false to include "dist" folder in search results
|
||||
},
|
||||
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
|
||||
"typescript.tsc.autoDetect": "off"
|
||||
}
|
||||
"files.exclude": {
|
||||
"out": false, // set this to true to hide the "out" folder with the compiled JS files
|
||||
"dist": false // set this to true to hide the "dist" folder with the compiled JS files
|
||||
},
|
||||
"search.exclude": {
|
||||
"out": true, // set this to false to include "out" folder in search results
|
||||
"dist": true // set this to false to include "dist" folder in search results
|
||||
},
|
||||
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
|
||||
"typescript.tsc.autoDetect": "off"
|
||||
}
|
||||
|
||||
@@ -4,56 +4,52 @@
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "watch",
|
||||
"dependsOn": [
|
||||
"npm: build:webview",
|
||||
"npm: watch:tsc",
|
||||
"npm: watch:esbuild"
|
||||
],
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "build:webview",
|
||||
"group": "build",
|
||||
"problemMatcher": [],
|
||||
"isBackground": true,
|
||||
"label": "npm: build:webview",
|
||||
"presentation": {
|
||||
"group": "watch",
|
||||
"reveal": "never"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch:esbuild",
|
||||
"group": "build",
|
||||
"problemMatcher": "$esbuild-watch",
|
||||
"isBackground": true,
|
||||
"label": "npm: watch:esbuild",
|
||||
"presentation": {
|
||||
"group": "watch",
|
||||
"reveal": "never"
|
||||
}
|
||||
},
|
||||
"label": "watch",
|
||||
"dependsOn": ["npm: build:webview", "npm: watch:tsc", "npm: watch:esbuild"],
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch:tsc",
|
||||
"group": "build",
|
||||
"problemMatcher": "$tsc-watch",
|
||||
"isBackground": true,
|
||||
"label": "npm: watch:tsc",
|
||||
"presentation": {
|
||||
"group": "watch",
|
||||
"reveal": "never"
|
||||
}
|
||||
},
|
||||
"type": "npm",
|
||||
"script": "build:webview",
|
||||
"group": "build",
|
||||
"problemMatcher": [],
|
||||
"isBackground": true,
|
||||
"label": "npm: build:webview",
|
||||
"presentation": {
|
||||
"group": "watch",
|
||||
"reveal": "never"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch:esbuild",
|
||||
"group": "build",
|
||||
"problemMatcher": "$esbuild-watch",
|
||||
"isBackground": true,
|
||||
"label": "npm: watch:esbuild",
|
||||
"presentation": {
|
||||
"group": "watch",
|
||||
"reveal": "never"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch:tsc",
|
||||
"group": "build",
|
||||
"problemMatcher": "$tsc-watch",
|
||||
"isBackground": true,
|
||||
"label": "npm: watch:tsc",
|
||||
"presentation": {
|
||||
"group": "watch",
|
||||
"reveal": "never"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch-tests",
|
||||
@@ -67,10 +63,7 @@
|
||||
},
|
||||
{
|
||||
"label": "tasks: watch-tests",
|
||||
"dependsOn": [
|
||||
"npm: watch",
|
||||
"npm: watch-tests"
|
||||
],
|
||||
"dependsOn": ["npm: watch", "npm: watch-tests"],
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
|
||||
@@ -31,12 +31,15 @@ webview-ui/package-lock.json
|
||||
webview-ui/node_modules/**
|
||||
**/.gitignore
|
||||
|
||||
# Ignore docs
|
||||
docs/**
|
||||
|
||||
# Fix issue where codicons don't get packaged (https://github.com/microsoft/vscode-extension-samples/issues/692)
|
||||
!node_modules/@vscode/codicons/dist/codicon.css
|
||||
!node_modules/@vscode/codicons/dist/codicon.ttf
|
||||
|
||||
# Include default themes JSON files used in getTheme
|
||||
!src/utils/default-themes/**
|
||||
!src/integrations/theme/default-themes/**
|
||||
|
||||
# Include icons
|
||||
!icons/**
|
||||
!assets/icons/**
|
||||
@@ -1,111 +1,11 @@
|
||||
# Change Log
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
All notable changes to the "claude-dev" extension will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
|
||||
and is generated by [Changie](https://github.com/miniscruff/changie).
|
||||
|
||||
<!-- Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. -->
|
||||
|
||||
## [1.8.0]
|
||||
|
||||
- You can now use '@' in the textarea to add context!
|
||||
- @url: Paste in a URL for the extension to fetch and convert to markdown, useful when you want to give Claude the latest docs!
|
||||
- @problems: Add workspace errors and warnings for Claude to fix, no more back-and-forth about debugging
|
||||
- @file: Adds a file's contents so you don't have to waste API requests approving read file (+ type to search files)
|
||||
- @folder: Adds folder's files all at once to speed up your workflow even more
|
||||
|
||||
## [1.7.0]
|
||||
|
||||
- Adds problems monitoring to keep Claude updated on linter/compiler/build issues, letting him proactively fix errors on his own! (adding missing imports, fixing type errors, etc.)
|
||||
|
||||
## [1.6.5]
|
||||
|
||||
- Adds support for OpenAI o1, Azure OpenAI, and Google Gemini (free for up to 15 requests per minute!)
|
||||
- Task header can now be collapsed to provide more space for viewing conversations
|
||||
- Adds fuzzy search and sorting to Task History, making it easier to find specific tasks
|
||||
|
||||
## [1.6.0]
|
||||
|
||||
- Commands now run directly in your terminal thanks to VSCode 1.93's new shell integration updates! Plus a new 'Proceed While Running' button to let Claude continue working while commands run, sending him new output along the way (i.e. letting him react to server errors as he edits files)
|
||||
|
||||
## [1.5.27]
|
||||
|
||||
- Claude's changes now appear in your file's Timeline, allowing you to easily view a diff of each edit. This is especially helpful if you want to revert to a previous version. No need for git—everything is tracked by VSCode's local history!
|
||||
- Updated system prompt to keep Claude from re-reading files unnecessarily
|
||||
|
||||
## [1.5.19]
|
||||
|
||||
- Adds support for OpenAI compatible API providers (e.g. Ollama!)
|
||||
|
||||
## [1.5.13]
|
||||
|
||||
- New terminal emulator! When Claude runs commands, you can now type directly in the terminal (+ support for Python environments)
|
||||
- Adds search to Task History
|
||||
|
||||
## [1.5.6]
|
||||
|
||||
- You can now edit Claude's changes before accepting! When he edits or creates a file, you can modify his changes directly in the right side of the diff view (+ hover over the 'Revert Block' arrow button in the center to undo `// rest of code here` shenanigans)
|
||||
|
||||
## [1.5.4]
|
||||
|
||||
- Adds support for reading .pdf and .docx files (try "turn my business_plan.docx into a company website")
|
||||
|
||||
## [1.5.0]
|
||||
|
||||
- Adds new `search_files` tool that lets Claude perform regex searches in your project, making it easy for him to refactor code, address TODOs and FIXMEs, remove dead code, and more!
|
||||
|
||||
## [1.4.0]
|
||||
|
||||
- Adds "Always allow read-only operations" setting to let Claude read files and view directories without needing approval (off by default)
|
||||
- Implement sliding window context management to keep tasks going past 200k tokens
|
||||
- Adds Google Cloud Vertex AI support and updates Claude 3.5 Sonnet max output to 8192 tokens for all providers.
|
||||
- Improves system prompt to gaurd against lazy edits (less "//rest of code here")
|
||||
|
||||
## [1.3.0]
|
||||
|
||||
- Adds task history
|
||||
|
||||
## [1.2.0]
|
||||
|
||||
- Adds support for Prompt Caching to significantly reduce costs and response times (currently only available through Anthropic API for Claude 3.5 Sonnet and Claude 3.0 Haiku)
|
||||
|
||||
## [1.1.1]
|
||||
|
||||
- Adds option to choose other Claude models (+ GPT-4o, DeepSeek, and Mistral if you use OpenRouter)
|
||||
- Adds option to add custom instructions to the end of the system prompt
|
||||
|
||||
## [1.1.0]
|
||||
|
||||
- Paste images in chat to use Claude's vision capabilities and turn mockups into fully functional applications or fix bugs with screenshots
|
||||
|
||||
## [1.0.9]
|
||||
|
||||
- Add support for OpenRouter and AWS Bedrock
|
||||
|
||||
## [1.0.8]
|
||||
|
||||
- Shows diff view of new or edited files right in the editor
|
||||
|
||||
## [1.0.7]
|
||||
|
||||
- Replace `list_files` and `analyze_project` with more explicit `list_files_top_level`, `list_files_recursive`, and `view_source_code_definitions_top_level` to get source code definitions only for files relevant to the task
|
||||
|
||||
## [1.0.6]
|
||||
|
||||
- Interact with CLI commands by sending messages to stdin and terminating long-running processes like servers
|
||||
- Export tasks to markdown files (useful as context for future tasks)
|
||||
|
||||
## [1.0.5]
|
||||
|
||||
- Claude now has context about vscode's visible editors and opened tabs
|
||||
|
||||
## [1.0.4]
|
||||
|
||||
- Open in the editor (using menu bar or `Claude Dev: Open In New Tab` in command palette) to see how Claude updates your workspace more clearly
|
||||
- New `analyze_project` tool to help Claude get a comprehensive overview of your project's source code definitions and file structure
|
||||
- Provide feedback to tool use like terminal commands and file edits
|
||||
- Updated max output tokens to 8192 so less lazy coding (`// rest of code here...`)
|
||||
- Added ability to retry failed API requests (helpful for rate limits)
|
||||
- Quality of life improvements like markdown rendering, memory optimizations, better theme support
|
||||
|
||||
## [0.0.6]
|
||||
|
||||
- Initial release
|
||||
## v0.1.0 - 2025-01-29
|
||||
### Added
|
||||
* new section to README about Changie
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
- The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
- Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at hi@cline.bot. All complaints
|
||||
will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
@@ -0,0 +1,82 @@
|
||||
# Contributing to Cline
|
||||
|
||||
We're thrilled you're interested in contributing to Cline. Whether you're fixing a bug, adding a feature, or improving our docs, every contribution makes Cline smarter! To keep our community vibrant and welcoming, all members must adhere to our [Code of Conduct](CODE_OF_CONDUCT.md).
|
||||
|
||||
## Reporting Bugs or Issues
|
||||
|
||||
Bug reports help make Cline better for everyone! Before creating a new issue, please [search existing ones](https://github.com/cline/cline/issues) to avoid duplicates. When you're ready to report a bug, head over to our [issues page](https://github.com/cline/cline/issues/new/choose) where you'll find a template to help you with filling out the relevant information.
|
||||
|
||||
<blockquote class='warning-note'>
|
||||
🔐 <b>Important:</b> If you discover a security vulnerability, please use the <a href="https://github.com/cline/cline/security/advisories/new">Github security tool to report it privately</a>.
|
||||
</blockquote>
|
||||
|
||||
## Deciding What to Work On
|
||||
|
||||
Looking for a good first contribution? Check out issues labeled ["good first issue"](https://github.com/cline/cline/labels/good%20first%20issue) or ["help wanted"](https://github.com/cline/cline/labels/help%20wanted). These are specifically curated for new contributors and areas where we'd love some help!
|
||||
|
||||
We also welcome contributions to our [documentation](https://github.com/cline/cline/tree/main/docs)! Whether it's fixing typos, improving existing guides, or creating new educational content - we'd love to build a community-driven repository of resources that helps everyone get the most out of Cline. You can start by diving into `/docs` and looking for areas that need improvement.
|
||||
|
||||
If you're planning to work on a bigger feature, please create a [feature request](https://github.com/cline/cline/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop) first so we can discuss whether it aligns with Cline's vision.
|
||||
|
||||
## Development Setup
|
||||
|
||||
1. **VS Code Extensions**
|
||||
|
||||
- When opening the project, VS Code will prompt you to install recommended extensions
|
||||
- These extensions are required for development - please accept all installation prompts
|
||||
- If you dismissed the prompts, you can install them manually from the Extensions panel
|
||||
|
||||
2. **Local Development**
|
||||
- Run `npm run install:all` to install dependencies
|
||||
- Run `npm run test` to run tests locally
|
||||
- Before submitting PR, run `npm run format:fix` to format your code
|
||||
|
||||
## Writing and Submitting Code
|
||||
|
||||
Anyone can contribute code to Cline, but we ask that you follow these guidelines to ensure your contributions can be smoothly integrated:
|
||||
|
||||
1. **Keep Pull Requests Focused**
|
||||
|
||||
- Limit PRs to a single feature or bug fix
|
||||
- Split larger changes into smaller, related PRs
|
||||
- Break changes into logical commits that can be reviewed independently
|
||||
|
||||
2. **Code Quality**
|
||||
|
||||
- Run `npm run lint` to check code style
|
||||
- Run `npm run format` to automatically format code
|
||||
- All PRs must pass CI checks which include both linting and formatting
|
||||
- Address any ESLint warnings or errors before submitting
|
||||
- Follow TypeScript best practices and maintain type safety
|
||||
|
||||
3. **Testing**
|
||||
|
||||
- Add tests for new features
|
||||
- Run `npm test` to ensure all tests pass
|
||||
- Update existing tests if your changes affect them
|
||||
- Include both unit tests and integration tests where appropriate
|
||||
|
||||
4. **Commit Guidelines**
|
||||
|
||||
- Write clear, descriptive commit messages
|
||||
- Use conventional commit format (e.g., "feat:", "fix:", "docs:")
|
||||
- Reference relevant issues in commits using #issue-number
|
||||
|
||||
5. **Before Submitting**
|
||||
|
||||
- Rebase your branch on the latest main
|
||||
- Ensure your branch builds successfully
|
||||
- Double-check all tests are passing
|
||||
- Review your changes for any debugging code or console logs
|
||||
|
||||
6. **Pull Request Description**
|
||||
- Clearly describe what your changes do
|
||||
- Include steps to test the changes
|
||||
- List any breaking changes
|
||||
- Add screenshots for UI changes
|
||||
|
||||
## Contribution Agreement
|
||||
|
||||
By submitting a pull request, you agree that your contributions will be licensed under the same license as the project ([Apache 2.0](LICENSE)).
|
||||
|
||||
Remember: Contributing to Cline isn't just about writing code - it's about being part of a community that's shaping the future of AI-assisted development. Let's build something amazing together! 🚀
|
||||
@@ -1,21 +1,201 @@
|
||||
MIT License
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
Copyright (c) 2024 Saoud Rizwan
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
1. Definitions.
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2024 Cline Bot Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,75 +1,156 @@
|
||||
# Claude Dev
|
||||
<div align="center"><sub>
|
||||
English | <a href="./locales/es/README.md" target="_blank">Español</a> | <a href="./locales/de/README.md" target="_blank">Deutsch</a> | <a href="./locales/ja/README.md" target="_blank">日本語</a> | <a href="./locales/zh-cn/README.md" target="_blank">简体中文</a> | <a href="./locales/zh-tw/README.md" target="_blank">繁體中文</a>
|
||||
</sub></div>
|
||||
|
||||
# Cline – \#1 on OpenRouter
|
||||
|
||||
<p align="center">
|
||||
<img src="https://media.githubusercontent.com/media/saoudrizwan/claude-dev/main/demo.gif" width="100%" />
|
||||
<img src="https://media.githubusercontent.com/media/cline/cline/main/assets/docs/demo.gif" width="100%" />
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev" target="_blank"><strong>Download VSCode Extension</strong></a> | <a href="https://discord.gg/claudedev" target="_blank"><strong>Join the Discord</strong></a>
|
||||
</p>
|
||||
<div align="center">
|
||||
<table>
|
||||
<tbody>
|
||||
<td align="center">
|
||||
<a href="https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev" target="_blank"><strong>Download on VS Marketplace</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://discord.gg/cline" target="_blank"><strong>Discord</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://www.reddit.com/r/cline/" target="_blank"><strong>r/cline</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/cline/cline/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop" target="_blank"><strong>Feature Requests</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://cline.bot/join-us" target="_blank"><strong>We're Hiring!</strong></a>
|
||||
</td>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
Thanks to [Claude 3.5 Sonnet's agentic coding capabilities](https://www-cdn.anthropic.com/fed9cc193a14b84131812372d8d5857f8f304c52/Model_Card_Claude_3_Addendum.pdf) Claude Dev can handle complex software development tasks step-by-step. With tools that let him create & edit files, explore complex projects, and execute terminal commands (after you grant permission), he can assist you in ways that go beyond simple code completion or tech support. While autonomous AI scripts traditionally run in sandboxed environments, Claude Dev provides a human-in-the-loop GUI to supervise every file changed and command executed, providing a safe and accessible way to explore the potential of agentic AI.
|
||||
Meet Cline, an AI assistant that can use your **CLI** a**N**d **E**ditor.
|
||||
|
||||
- Paste images in chat to use Claude's vision capabilities and turn mockups into fully functional applications or fix bugs with screenshots
|
||||
- Review and edit diffs of every change Claude makes right in the editor, or provide feedback in chat until you're satisfied with the result
|
||||
- Executes commands directly in your terminal, keeping Claude updated on any output as he works (letting him react to server errors!)
|
||||
- Monitors workspace problems to keep Claude updated on linter/compiler/build issues, letting him proactively fix errors on his own (adding missing imports, fixing syntax errors, etc.)
|
||||
- Presents permission buttons (like 'Approve terminal command') before tool use or sending information to the API
|
||||
- Keep track of total tokens and API usage cost for the entire task loop and individual requests
|
||||
- When a task is completed, Claude determines if he can present the result to you with a terminal command like `open -a "Google Chrome" index.html`, which you run with a click of a button
|
||||
Thanks to [Claude 3.5 Sonnet's agentic coding capabilities](https://www-cdn.anthropic.com/fed9cc193a14b84131812372d8d5857f8f304c52/Model_Card_Claude_3_Addendum.pdf), Cline can handle complex software development tasks step-by-step. With tools that let him create & edit files, explore large projects, use the browser, and execute terminal commands (after you grant permission), he can assist you in ways that go beyond code completion or tech support. Cline can even use the Model Context Protocol (MCP) to create new tools and extend his own capabilities. While autonomous AI scripts traditionally run in sandboxed environments, this extension provides a human-in-the-loop GUI to approve every file change and terminal command, providing a safe and accessible way to explore the potential of agentic AI.
|
||||
|
||||
_**Pro tip**: Use the `Cmd + Shift + P` shortcut to open the command palette and type `Claude Dev: Open In New Tab` to start a new task right in the editor._
|
||||
1. Enter your task and add images to convert mockups into functional apps or fix bugs with screenshots.
|
||||
2. Cline starts by analyzing your file structure & source code ASTs, running regex searches, and reading relevant files to get up to speed in existing projects. By carefully managing what information is added to context, Cline can provide valuable assistance even for large, complex projects without overwhelming the context window.
|
||||
3. Once Cline has the information he needs, he can:
|
||||
- Create and edit files + monitor linter/compiler errors along the way, letting him proactively fix issues like missing imports and syntax errors on his own.
|
||||
- Execute commands directly in your terminal and monitor their output as he works, letting him e.g., react to dev server issues after editing a file.
|
||||
- For web development tasks, Cline can launch the site in a headless browser, click, type, scroll, and capture screenshots + console logs, allowing him to fix runtime errors and visual bugs.
|
||||
4. When a task is completed, Cline will present the result to you with a terminal command like `open -a "Google Chrome" index.html`, which you run with a click of a button.
|
||||
|
||||
## How it works
|
||||
> [!TIP]
|
||||
> Use the `CMD/CTRL + Shift + P` shortcut to open the command palette and type "Cline: Open In New Tab" to open the extension as a tab in your editor. This lets you use Cline side-by-side with your file explorer, and see how he changes your workspace more clearly.
|
||||
|
||||
Claude Dev uses an autonomous task execution loop with chain-of-thought prompting and access to powerful tools that give him the ability to accomplish nearly any task. Start by providing a task and the loop fires off, where Claude might use certain tools (with your permission) to accomplish each step in his thought process.
|
||||
---
|
||||
|
||||
### Tools
|
||||
<img align="right" width="340" src="https://github.com/user-attachments/assets/3cf21e04-7ce9-4d22-a7b9-ba2c595e88a4">
|
||||
|
||||
Claude Dev has access to the following capabilities:
|
||||
### Use any API and Model
|
||||
|
||||
1. **`execute_command`**: Execute terminal commands on the system (only with your permission, output is streamed into the chat)
|
||||
2. **`read_file`**: Read the contents of a file at the specified path
|
||||
3. **`write_to_file`**: Write content to a file at the specified path, automatically creating any necessary directories
|
||||
4. **`list_files`**: List all paths for files in the specified directory. When `recursive = true`, it recursively lists all files in the directory and its nested folders (excludes files in .gitignore). When `recursive = false`, it lists only top-level files (useful for generic file operations like retrieving a file from your Desktop).
|
||||
5. **`list_code_definition_names`**: Parses all source code files at the top level of the specified directory to extract names of key elements like classes and functions (see more below)
|
||||
6. **`search_files`**: Search files in a specified directory for text that matches a given regex pattern (useful for refactoring code, addressing TODOs and FIXMEs, removing dead code, etc.)
|
||||
7. **`ask_followup_question`**: Ask the user a question to gather additional information needed to complete a task (due to the autonomous nature of the program, this isn't a typical chatbot–Claude Dev must explicitly interrupt his task loop to ask for more information)
|
||||
8. **`attempt_completion`**: Present the result to the user after completing a task, potentially with a terminal command to kickoff a demonstration
|
||||
Cline supports API providers like OpenRouter, Anthropic, OpenAI, Google Gemini, AWS Bedrock, Azure, and GCP Vertex. You can also configure any OpenAI compatible API, or use a local model through LM Studio/Ollama. If you're using OpenRouter, the extension fetches their latest model list, allowing you to use the newest models as soon as they're available.
|
||||
|
||||
### Working in Existing Projects
|
||||
The extension also keeps track of total tokens and API usage cost for the entire task loop and individual requests, keeping you informed of spend every step of the way.
|
||||
|
||||
When given a task in an existing project, Claude will look for the most relevant files to read and edit the same way you or I would–by first looking at the names of directories, files, classes, and functions since these names tend to reflect their purpose and role within the broader system, and often encapsulate high-level concepts and relationships that help understand a project's overall architecture. With tools like `list_code_definition_names` and `search_files`, Claude is able to extract names of various elements in a project to determine what files are most relevant to a given task without you having to mention `@file`s or `@folder`s yourself.
|
||||
<!-- Transparent pixel to create line break after floating image -->
|
||||
|
||||
1. **File Structure**: When a task is started, Claude is given an overview of your project's file structure. It turns out Claude 3.5 Sonnet is _really_ good at inferring what it needs to process further just from these file names alone.
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
2. **Source Code Definitions**: Claude may then use the `list_code_definition_names` tool on specific directories of interest. This tool uses [tree-sitter](https://github.com/tree-sitter/tree-sitter) to parse source code with custom tag queries that extract names of classes, functions, methods, and other definitions. It works by first identifying source code files that tree-sitter can parse (currently supports `python`, `javascript`, `typescript`, `ruby`, `go`, `java`, `php`, `rust`, `c`, `c++`, `c#`, `swift`), then parsing each file into an abstract syntax tree, and finally applying a language-specific query to extract definition names (you can see the exact query used for each language in `src/parse-source-code/queries`). The results are formatted into a concise & readable output that Claude can easily interpret to quickly understand the code's structure and purpose.
|
||||
<img align="left" width="370" src="https://github.com/user-attachments/assets/81be79a8-1fdb-4028-9129-5fe055e01e76">
|
||||
|
||||
3. **Search Files**: Claude can also use the `search_files` tool to search for specific patterns or content across multiple files. This tool uses [ripgrep](https://github.com/BurntSushi/ripgrep) to perform regex searches on files in a specified directory. The results are formatted into a concise & readable output that Claude can easily interpret to quickly understand the code's structure and purpose. This can be useful for tasks like refactoring function names, updating imports, addressing TODOs and FIXMEs, etc.
|
||||
### Run Commands in Terminal
|
||||
|
||||
4. **Read Relevant Files**: With insights gained from the names of various files and source code definitions, Claude can then use the `read_file` tool to examine specific files that are most relevant to the task at hand.
|
||||
Thanks to the new [shell integration updates in VSCode v1.93](https://code.visualstudio.com/updates/v1_93#_terminal-shell-integration-api), Cline can execute commands directly in your terminal and receive the output. This allows him to perform a wide range of tasks, from installing packages and running build scripts to deploying applications, managing databases, and executing tests, all while adapting to your dev environment & toolchain to get the job done right.
|
||||
|
||||
By carefully managing what information is added to context, Claude can provide valuable assistance even for complex, large-scale projects without overwhelming its context window.
|
||||
For long running processes like dev servers, use the "Proceed While Running" button to let Cline continue in the task while the command runs in the background. As Cline works he’ll be notified of any new terminal output along the way, letting him react to issues that may come up, such as compile-time errors when editing files.
|
||||
|
||||
### Only With Your Permission
|
||||
<!-- Transparent pixel to create line break after floating image -->
|
||||
|
||||
Claude always asks for your permission first before any tools are executed or information is sent back to the API. This puts you in control of this agentic loop, every step of the way.
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||

|
||||
<img align="right" width="400" src="https://github.com/user-attachments/assets/c5977833-d9b8-491e-90f9-05f9cd38c588">
|
||||
|
||||
## Contribution
|
||||
### Create and Edit Files
|
||||
|
||||
Paul Graham said it best, "if you build something now that barely works with AI, the next models will make it _really_ work." I've built this project with the assumption that scaling laws will continue to improve the quality (and cost) of AI models, and what might be difficult for Claude 3.5 Sonnet today will be effortless for future generations. That is the design philosophy I'd like to develop this project with, so it will always be updated with the best models, tools, and capabilities available–without wasting effort on implementing stopgaps like cheaper agents. With that said, I'm always open to suggestions and feedback, so please feel free to contribute to this project by submitting issues and pull requests.
|
||||
Cline can create and edit files directly in your editor, presenting you a diff view of the changes. You can edit or revert Cline's changes directly in the diff view editor, or provide feedback in chat until you're satisfied with the result. Cline also monitors linter/compiler errors (missing imports, syntax errors, etc.) so he can fix issues that come up along the way on his own.
|
||||
|
||||
To build Claude Dev locally, follow these steps:
|
||||
All changes made by Cline are recorded in your file's Timeline, providing an easy way to track and revert modifications if needed.
|
||||
|
||||
1. Clone the repository:
|
||||
<!-- Transparent pixel to create line break after floating image -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="370" src="https://github.com/user-attachments/assets/bc2e85ba-dfeb-4fe6-9942-7cfc4703cbe5">
|
||||
|
||||
### Use the Browser
|
||||
|
||||
With Claude 3.5 Sonnet's new [Computer Use](https://www.anthropic.com/news/3-5-models-and-computer-use) capability, Cline can launch a browser, click elements, type text, and scroll, capturing screenshots and console logs at each step. This allows for interactive debugging, end-to-end testing, and even general web use! This gives him autonomy to fixing visual bugs and runtime issues without you needing to handhold and copy-pasting error logs yourself.
|
||||
|
||||
Try asking Cline to "test the app", and watch as he runs a command like `npm run dev`, launches your locally running dev server in a browser, and performs a series of tests to confirm that everything works. [See a demo here.](https://x.com/sdrzn/status/1850880547825823989)
|
||||
|
||||
<!-- Transparent pixel to create line break after floating image -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="350" src="https://github.com/user-attachments/assets/ac0efa14-5c1f-4c26-a42d-9d7c56f5fadd">
|
||||
|
||||
### "add a tool that..."
|
||||
|
||||
Thanks to the [Model Context Protocol](https://github.com/modelcontextprotocol), Cline can extend his capabilities through custom tools. While you can use [community-made servers](https://github.com/modelcontextprotocol/servers), Cline can instead create and install tools tailored to your specific workflow. Just ask Cline to "add a tool" and he will handle everything, from creating a new MCP server to installing it into the extension. These custom tools then become part of Cline's toolkit, ready to use in future tasks.
|
||||
|
||||
- "add a tool that fetches Jira tickets": Retrieve ticket ACs and put Cline to work
|
||||
- "add a tool that manages AWS EC2s": Check server metrics and scale instances up or down
|
||||
- "add a tool that pulls the latest PagerDuty incidents": Fetch details and ask Cline to fix bugs
|
||||
|
||||
<!-- Transparent pixel to create line break after floating image -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="360" src="https://github.com/user-attachments/assets/7fdf41e6-281a-4b4b-ac19-020b838b6970">
|
||||
|
||||
### Add Context
|
||||
|
||||
**`@url`:** Paste in a URL for the extension to fetch and convert to markdown, useful when you want to give Cline the latest docs
|
||||
|
||||
**`@problems`:** Add workspace errors and warnings ('Problems' panel) for Cline to fix
|
||||
|
||||
**`@file`:** Adds a file's contents so you don't have to waste API requests approving read file (+ type to search files)
|
||||
|
||||
**`@folder`:** Adds folder's files all at once to speed up your workflow even more
|
||||
|
||||
<!-- Transparent pixel to create line break after floating image -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="350" src="https://github.com/user-attachments/assets/140c8606-d3bf-41b9-9a1f-4dbf0d4c90cb">
|
||||
|
||||
### Checkpoints: Compare and Restore
|
||||
|
||||
As Cline works through a task, the extension takes a snapshot of your workspace at each step. You can use the 'Compare' button to see a diff between the snapshot and your current workspace, and the 'Restore' button to roll back to that point.
|
||||
|
||||
For example, when working with a local web server, you can use 'Restore Workspace Only' to quickly test different versions of your app, then use 'Restore Task and Workspace' when you find the version you want to continue building from. This lets you safely explore different approaches without losing progress.
|
||||
|
||||
<!-- Transparent pixel to create line break after floating image -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
## Contributing
|
||||
|
||||
To contribute to the project, start with our [Contributing Guide](CONTRIBUTING.md) to learn the basics. You can also join our [Discord](https://discord.gg/cline) to chat with other contributors in the `#contributors` channel. If you're looking for full-time work, check out our open positions on our [careers page](https://cline.bot/join-us)!
|
||||
|
||||
<details>
|
||||
<summary>Local Development Instructions</summary>
|
||||
|
||||
1. Clone the repository _(Requires [git-lfs](https://git-lfs.com/))_:
|
||||
```bash
|
||||
git clone https://github.com/saoudrizwan/claude-dev.git
|
||||
git clone https://github.com/cline/cline.git
|
||||
```
|
||||
2. Open the project in VSCode:
|
||||
```bash
|
||||
code claude-dev
|
||||
code cline
|
||||
```
|
||||
3. Install the necessary dependencies for the extension and webview-gui:
|
||||
```bash
|
||||
@@ -77,30 +158,33 @@ To build Claude Dev locally, follow these steps:
|
||||
```
|
||||
4. Launch by pressing `F5` (or `Run`->`Start Debugging`) to open a new VSCode window with the extension loaded. (You may need to install the [esbuild problem matchers extension](https://marketplace.visualstudio.com/items?itemName=connor4312.esbuild-problem-matchers) if you run into issues building the project.)
|
||||
|
||||
## Reviews
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Creating a Pull Request</summary>
|
||||
|
||||
1. Before creating a PR, generate a changelog entry using [Changie](https://changie.dev/):
|
||||
```bash
|
||||
npm run changie new
|
||||
```
|
||||
This will prompt you for:
|
||||
- Kind of change (Added, Changed, Deprecated, Removed, Fixed, Security)
|
||||
- `Added` → triggers minor version bump (1.0.0 → 1.1.0)
|
||||
- `Changed`, `Deprecated`, `Removed`, `Fixed`, `Security` → triggers patch version bump (1.0.0 → 1.0.1)
|
||||
- Breaking changes → triggers major version bump (1.0.0 → 2.0.0)
|
||||
- Description of your changes
|
||||
- Issue number (if applicable)
|
||||
|
||||
2. Commit your changes and the generated `.changes` file
|
||||
|
||||
3. Push your branch and create a PR on GitHub. Our CI will:
|
||||
- Run tests and checks
|
||||
- When merged to main, automatically batch changelog entries
|
||||
- Create a version PR with the updated CHANGELOG.md
|
||||
|
||||
</details>
|
||||
|
||||
- ["VSCode + ClaudeDev + Continue: Stop Paying for Cursor with this OPENSOURCE & LOCAL Alternative"](https://www.youtube.com/watch?v=ucalLC8k94w), ["Claude Dev: This Coding Agent can Generate Applications Within VS Code!"](https://www.youtube.com/watch?v=ufq6sHGe0zs), ["ClaudeDev (Upgraded) : The BEST Coding Agent just got OLLAMA Support, Groq & Other Cool Updates!"](https://www.youtube.com/watch?v=QOG8qArZakg), ["ClaudeDev + NextJS + Supabase: Generate FULL-STACK Apps with Claude 3.5 Sonnet"](https://www.youtube.com/watch?v=GeZBfO1kxA4), ["ClaudeDev + Gemini : Generate Applications for FREE with Gemini 1.5 Pro / Flash!"](https://www.youtube.com/watch?v=FAFmP82bhDA), ["ClaudeDev (Upgraded) : The BEST Coding Agent just got Opensource LLM & Multimodal Support + Caching!"](https://www.youtube.com/watch?v=66b3qHPnKWM) by [AICodeKing](https://www.youtube.com/@AICodeKing)
|
||||
- ["ClaudeDev: NEW Coding Agent Can Generate Applications within VS Code!"](https://www.youtube.com/watch?v=UNsQHosbIoE), ["VSCode + ClaudeDev: FREE Alternative Thats OPENSOURCE & LOCAL!"](https://www.youtube.com/watch?v=-vBNjoi_gJg) by [WorldofAI](https://www.youtube.com/@intheworldofai)
|
||||
- ["Claude Sonnet 3.5 Artifacts in VSCode With This Extension"](https://www.youtube.com/watch?v=5FbZ8ALfSTs) by [CoderOne](https://www.youtube.com/@CoderOne)
|
||||
- ["Fully automated game development with a single prompt!"](https://www.youtube.com/watch?v=n18L9VFhNDo), ["Claude Dev fully automated writing code to develop chatbots! Beyond Copilot!"](https://www.youtube.com/watch?v=Us6LQzKmgfs) by [AIsuperdomain](https://www.youtube.com/@AIsuperdomain)
|
||||
- ["ClaudeDev: This Mind-Blowing Coding Agent Can Build SaaS Apps in Minutes!"](https://www.youtube.com/watch?v=Ki0nuOeUpT0) by [AI for Devs](https://www.youtube.com/@ai-for-devs)
|
||||
- ["Claude Dev Is Mindblowing. The Best Coding Assistant tool?"](https://www.youtube.com/watch?v=Vp1Z3VGZroA), ["Combining Claude Dev With Google Gemini To Build Fast With Low Effort"](https://www.youtube.com/watch?v=cAfunEHLees), ["Browser Automation Made Easy With Claude Dev"](https://www.youtube.com/watch?v=EQ4O8rUOqZs), ["CREATE THE PERFECT CODE FOR YOU"](https://www.youtube.com/watch?v=HA5e0YIBOjk), ["The Most Powerful AI Coding Assistant Is Now Available With Local Models"](https://www.youtube.com/watch?v=UpTGEsY1Bus) by [Yaron Been](https://www.youtube.com/@ecomxfactor-YaronBeen)
|
||||
- ["Meet Claude Dev — An Open-Source AI Programmer In VS Code"](https://generativeai.pub/meet-claude-dev-an-open-source-autonomous-ai-programmer-in-vs-code-f457f9821b7b) and ["Build games with zero code using Claude Dev in VS Code"](https://www.youtube.com/watch?v=VT-JYVi81ew) by [Jim Clyde Monge](https://jimclydemonge.medium.com/)
|
||||
- ["Claude Dev Builds NextJS App! Continue Dev & GitHub Copilot Open-Source Alternative"](https://www.youtube.com/watch?v=Rv0wJZRpnCQ) by [Josh Pocock](https://www.youtube.com/@joshfpocock)
|
||||
- ["ClaudeDev: The Ultimate Coding Agent for VS Code"](https://www.youtube.com/watch?v=aq0yw_DtphQ) by [Blas](https://www.youtube.com/@blascerecer)
|
||||
- ["I Built My First Web App in One Day Using Claude Dev Extension – Mind Blown!"](https://www.reddit.com/r/ClaudeAI/comments/1eqo3nk/i_built_my_first_web_app_in_one_day_using_claude/)
|
||||
- ["AI Development with Claude Dev"](https://www.linkedin.com/pulse/ai-development-claude-dev-shannon-lal-3ql3e/) by Shannon Lal
|
||||
- ["Code Smarter with Claude Dev: An AI Programmer for Your Projects"](https://www.linkedin.com/pulse/code-smarter-claude-dev-ai-programmer-your-projects-iana-detochka-jiqpe) by Iana D.
|
||||
- [Claude Dev also hit top 10 posts of all time on r/ClaudeAI](https://www.reddit.com/r/ClaudeAI/comments/1e3h0f1/my_submission_to_anthropics_build_with_claude/)
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details.
|
||||
|
||||
## Questions?
|
||||
|
||||
Contact me on X <a href="https://x.com/sdrzn" target="_blank">@sdrzn</a>. Please create an <a href="https://github.com/saoudrizwan/claude-dev/issues">issue</a> if you come across a bug or would like a feature to be added.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
Special thanks to Anthropic for providing the model that powers this extension.
|
||||
[Apache 2.0 © 2024 Cline Bot Inc.](./LICENSE)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d426d600fa80e9ac237cbad6b3f7f47a4aa2005d5218184e6b9565a8ee46d1ba
|
||||
size 19108207
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="92px" height="96px" viewBox="0 0 92 96" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Group Copy 2</title>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="icon-copy" transform="translate(-34, -40)" fill="#24292F">
|
||||
<g id="Group-Copy-2" transform="translate(34, 40.5)">
|
||||
<g id="Group-3-Copy-4" transform="translate(0, 0)">
|
||||
<path d="M65.4492701,16.3 C76.3374701,16.3 85.1635558,25.16479 85.1635558,36.1 L85.1635558,42.7 L90.9027661,54.1647464 C91.4694141,55.2966923 91.4668177,56.6300535 90.8957658,57.7597839 L85.1635558,69.1 L85.1635558,75.7 C85.1635558,86.63554 76.3374701,95.5 65.4492701,95.5 L26.0206986,95.5 C15.1328272,95.5 6.30641291,86.63554 6.30641291,75.7 L6.30641291,69.1 L0.448507752,57.7954874 C-0.14693501,56.6464093 -0.149634367,55.2802504 0.441262896,54.1288283 L6.30641291,42.7 L6.30641291,36.1 C6.30641291,25.16479 15.1328272,16.3 26.0206986,16.3 L65.4492701,16.3 Z M62.9301895,22 L29.189529,22 C19.8723267,22 12.3191987,29.5552188 12.3191987,38.875 L12.3191987,44.5 L7.44288578,53.9634655 C6.84794449,55.1180686 6.85066096,56.4896598 7.45017099,57.6418974 L12.3191987,67 L12.3191987,72.625 C12.3191987,81.9450625 19.8723267,89.5 29.189529,89.5 L62.9301895,89.5 C72.2476729,89.5 79.8005198,81.9450625 79.8005198,72.625 L79.8005198,67 L84.5682187,57.6061395 C85.1432011,56.473244 85.1458141,55.1345713 84.5752587,53.9994398 L79.8005198,44.5 L79.8005198,38.875 C79.8005198,29.5552188 72.2476729,22 62.9301895,22 Z" id="Combined-Shape" fill-rule="nonzero"></path>
|
||||
<circle id="Oval" cx="45.7349843" cy="11" r="11"></circle>
|
||||
</g>
|
||||
<rect id="Rectangle-Copy" stroke="#24292F" stroke-width="8" x="31" y="44.5" width="5" height="22" rx="2.5"></rect>
|
||||
<rect id="Rectangle-Copy-2" stroke="#24292F" stroke-width="8" x="55" y="44.5" width="5" height="22" rx="2.5"></rect>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 902 B |
|
After Width: | Height: | Size: 666 B |
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d2b5362be3f276597e89b5be4b00676e11a8bd1377e2530d3d1ab306e2e39181
|
||||
size 20554677
|
||||
@@ -0,0 +1,99 @@
|
||||
# Cline Privacy Policy
|
||||
|
||||
Cline Bot Inc. ("Cline," "we," "our," and/or "us") values the privacy of individuals who use our VS Code extension and related services (collectively, our "Services"). This privacy policy explains how we collect, use, and disclose information from users of our Services.
|
||||
|
||||
## Key Points
|
||||
|
||||
- Cline operates entirely client-side as a VS Code extension
|
||||
- No code or data is collected, stored, or transmitted to Cline's servers
|
||||
- Your data is only sent to your chosen AI provider (e.g., Anthropic, OpenAI) when you explicitly request assistance
|
||||
- All processing happens locally on your machine
|
||||
- API keys are stored securely in VS Code's built-in settings storage
|
||||
|
||||
## Information We Process
|
||||
|
||||
### A. Information You Provide
|
||||
|
||||
- **API Keys**: When you choose to use certain AI model providers (OpenRouter, Anthropic, OpenAI, etc.), you provide API keys. These are stored securely and locally in your VS Code settings.
|
||||
- **Communications**: If you contact us directly (e.g., via Discord or email), we may receive information like your name, email address, and message contents.
|
||||
|
||||
### B. Information Processing
|
||||
|
||||
Cline functions solely as a client-side VS Code extension that facilitates communication between your editor and your chosen AI model provider:
|
||||
|
||||
1. **File Contents**:
|
||||
|
||||
- Only sent to your chosen AI provider when you explicitly request assistance
|
||||
- Never stored or transmitted to Cline's servers
|
||||
- Only the specific files/content you select are included
|
||||
|
||||
2. **Terminal Commands**:
|
||||
|
||||
- Processed entirely locally on your machine
|
||||
- Require explicit user confirmation before execution
|
||||
- No command history is transmitted to Cline
|
||||
|
||||
3. **Browser Integration**:
|
||||
- Screenshots and console logs are processed locally
|
||||
- Temporary data is cleared after task completion
|
||||
|
||||
## Data Security
|
||||
|
||||
1. **Local-Only Processing**:
|
||||
|
||||
- All operations happen on your local machine
|
||||
- No central servers or data collection
|
||||
- No telemetry or usage statistics gathered
|
||||
- No account creation required
|
||||
|
||||
2. **API Key Security**:
|
||||
|
||||
- Stored using VS Code's secure settings storage system
|
||||
- Never transmitted to Cline's servers
|
||||
- You can remove/modify keys at any time
|
||||
|
||||
3. **User Control**:
|
||||
- Explicit approval required for file changes
|
||||
- Terminal commands require confirmation
|
||||
- Browser actions need explicit permission
|
||||
- You control which AI provider to use
|
||||
|
||||
## Communication with AI Providers
|
||||
|
||||
When you request assistance:
|
||||
|
||||
1. Selected content is sent directly to your chosen AI provider
|
||||
2. No data passes through Cline's servers
|
||||
3. Provider's own privacy policy applies to this communication:
|
||||
- [Anthropic Privacy Policy](https://www.anthropic.com/privacy)
|
||||
- [OpenAI Privacy Policy](https://openai.com/privacy)
|
||||
- [OpenRouter Privacy Policy](https://openrouter.ai/privacy)
|
||||
|
||||
## Error Handling & Debugging
|
||||
|
||||
- Error logs are processed locally
|
||||
- No automatic error reporting to Cline
|
||||
- You control what information to include when reporting issues
|
||||
|
||||
## Children's Privacy
|
||||
|
||||
We do not knowingly collect, maintain, or use personal information from children under 18 years of age, and no part of our Service(s) is directed to children. If you learn that a child has provided us with personal information in violation of this Privacy Policy, then you may alert us at support@cline.bot.
|
||||
|
||||
## Changes to Privacy Policy
|
||||
|
||||
We will post any changes to this policy on our GitHub repository. Significant changes will be announced in our Discord community.
|
||||
|
||||
## Security Concerns & Auditing
|
||||
|
||||
- Cline is open source and available for security audit
|
||||
- Our client-side architecture ensures no central point of data collection
|
||||
- You can inspect exactly what data is being sent to AI providers
|
||||
- Enterprise users can implement additional access controls through VS Code
|
||||
|
||||
## Contact Us
|
||||
|
||||
For privacy-related questions or concerns:
|
||||
|
||||
- Open an issue on our [GitHub repository](https://github.com/cline/cline)
|
||||
- Join our [Discord community](https://discord.gg/cline)
|
||||
- Email: support@cline.bot
|
||||
@@ -0,0 +1,38 @@
|
||||
# Cline Documentation
|
||||
|
||||
Welcome to the Cline documentation - your comprehensive guide to using and extending Cline's capabilities. Here you'll find resources to help you get started, improve your skills, and contribute to the project.
|
||||
|
||||
## Getting Started
|
||||
|
||||
- **New to coding?** We've prepared a gentle introduction:
|
||||
- [Getting Started for New Coders](getting-started-new-coders/README.md)
|
||||
|
||||
## Improving Your Prompting Skills
|
||||
|
||||
- **Want to communicate more effectively with Cline?** Explore:
|
||||
- [Prompt Engineering Guide](prompting/README.md)
|
||||
- [Cline Memory Bank](prompting/custom%20instructions%20library/cline-memory-bank.md)
|
||||
|
||||
## Exploring Cline's Tools
|
||||
|
||||
- **Understand Cline's capabilities:**
|
||||
|
||||
- [Cline Tools Guide](tools/cline-tools-guide.md)
|
||||
|
||||
- **Extend Cline with MCP Servers:**
|
||||
- [MCP Overview](mcp/README.md)
|
||||
- [Building MCP Servers from GitHub](mcp/mcp-server-from-github.md)
|
||||
- [Building Custom MCP Servers](mcp/mcp-server-from-scratch.md)
|
||||
|
||||
## Contributing to Cline
|
||||
|
||||
- **Interested in contributing?** We welcome your input:
|
||||
- Feel free to submit a pull request
|
||||
- [Contribution Guidelines](CONTRIBUTING.md)
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- **Cline GitHub Repository:** [https://github.com/cline/cline](https://github.com/cline/cline)
|
||||
- **MCP Documentation:** [https://modelcontextprotocol.org/docs](https://modelcontextprotocol.org/docs)
|
||||
|
||||
We're always looking to improve this documentation. If you have suggestions or find areas that could be enhanced, please let us know. Your feedback helps make Cline better for everyone.
|
||||
@@ -0,0 +1,92 @@
|
||||
# Getting Started with Cline | New Coders
|
||||
|
||||
Welcome to Cline! This guide will help you get set up and start using Cline to build your first project.
|
||||
|
||||
## What You'll Need
|
||||
|
||||
Before you begin, make sure you have the following:
|
||||
|
||||
- **VS Code:** A free, powerful code editor.
|
||||
- [Download VS Code](https://code.visualstudio.com/)
|
||||
- **Development Tools:** Essential software for coding (Homebrew, Node.js, Git, etc.).
|
||||
- Follow our [Installing Essential Development Tools](installing-dev-essentials.md) guide to set these up with Cline's help (after getting setup here)
|
||||
- Cline will guide you through installing everything you need
|
||||
- **Cline Projects Folder:** A dedicated folder for all your Cline projects.
|
||||
- On macOS: Create a folder named "Cline" in your Documents folder
|
||||
- Path: `/Users/[your-username]/Documents/Cline`
|
||||
- On Windows: Create a folder named "Cline" in your Documents folder
|
||||
- Path: `C:\Users\[your-username]\Documents\Cline`
|
||||
- Inside this Cline folder, create separate folders for each project
|
||||
- Example: `Documents/Cline/workout-app` for a workout tracking app
|
||||
- Example: `Documents/Cline/portfolio-website` for your portfolio
|
||||
- **Cline Extension in VS Code:** The Cline extension installed in VS Code.
|
||||
|
||||
- Here's a [tutorial](https://www.youtube.com/watch?v=N4td-fKhsOQ) on everything you need to get started.
|
||||
|
||||
## Step-by-Step Setup
|
||||
|
||||
Follow these steps to get Cline up and running:
|
||||
|
||||
1. **Open VS Code:** Launch the VS Code application. If VS Code shows "Running extensions might...", click "Allow".
|
||||
|
||||
2. **Open Your Cline Folder:** In VS Code, open the Cline folder you created in Documents.
|
||||
|
||||
3. **Navigate to Extensions:** Click on the Extensions icon in the Activity Bar on the side of VS Code.
|
||||
|
||||
4. **Search for 'Cline':** In the Extensions search bar, type "Cline".
|
||||
|
||||
5. **Install the Extension:** Click the "Install" button next to the Cline extension.
|
||||
|
||||
6. **Open Cline:** Once installed, you can open Cline in a few ways:
|
||||
- Click the Cline icon in the Activity Bar.
|
||||
- Use the command palette (`CMD/CTRL + Shift + P`) and type "Cline: Open In New Tab" to open Cline as a tab in your editor. This is recommended for a better view.
|
||||
- **Troubleshooting:** If you don't see the Cline icon, try restarting VS Code.
|
||||
- **What You'll See:** You should see the Cline chat window appear in your VS Code editor.
|
||||
|
||||

|
||||
|
||||
## Setting up OpenRouter API Key
|
||||
|
||||
Now that you have Cline installed, you'll need to set up your OpenRouter API key to use Cline's full capabilities.
|
||||
|
||||
1. **Get your OpenRouter API Key:**
|
||||
- [Get your OpenRouter API Key](https://openrouter.ai/)
|
||||
2. **Input Your OpenRouter API Key:**
|
||||
- Navigate to the settings button in the Cline extension.
|
||||
- Input your OpenRouter API key.
|
||||
- Select your preferred API model.
|
||||
- **Recommended Models for Coding:**
|
||||
- `anthropic/claude-3.5-sonnet`: Most used for coding tasks.
|
||||
- `google/gemini-2.0-flash-exp:free`: A free option for coding.
|
||||
- `deepseek/deepseek-chat`: SUPER CHEAP, almost as good as 3.5 sonnet
|
||||
- [OpenRouter Model Rankings](https://openrouter.ai/rankings/programming)
|
||||
|
||||
## Your First Interaction with Cline
|
||||
|
||||
Now you're ready to start building with Cline. Let's create your first project folder and build something! Copy and paste the following prompt into the Cline chat window:
|
||||
|
||||
```
|
||||
Hey Cline! Could you help me create a new project folder called "hello-world" in my Cline directory and make a simple webpage that says "Hello World" in big blue text?
|
||||
```
|
||||
|
||||
**What You'll See:** Cline will help you create the project folder and set up your first webpage.
|
||||
|
||||
## Tips for Working with Cline
|
||||
|
||||
- **Ask Questions:** If you're unsure about something, don't hesitate to ask Cline!
|
||||
- **Use Screenshots:** Cline can understand images, so feel free to use screenshots to show him what you're working on.
|
||||
- **Copy and Paste Errors:** If you encounter errors, copy and paste the error messages into Cline's chat. This will help him understand the issue and provide a solution.
|
||||
- **Speak Plainly:** Cline is designed to understand plain, non-technical language. Feel free to describe your ideas in your own words, and Cline will translate them into code.
|
||||
|
||||
## FAQs
|
||||
|
||||
- **What is the Terminal?** The terminal is a text-based interface for interacting with your computer. It allows you to run commands to perform various tasks, such as installing packages, running scripts, and managing files. Cline uses the terminal to execute commands and interact with your development environment.
|
||||
- **How Does the Codebase Work?** (This section will be expanded based on common questions from new coders)
|
||||
|
||||
## Still Struggling?
|
||||
|
||||
Feel free to contact me, and I'll help you get started with Cline.
|
||||
|
||||
nick | 608-558-2410
|
||||
|
||||
Join our Discord community: [https://discord.gg/cline](https://discord.gg/cline)
|
||||
@@ -0,0 +1,105 @@
|
||||
# Installing Essential Development Tools with Cline | New Coders
|
||||
|
||||
When you start coding, you'll need some essential development tools installed on your computer. Cline can help you install everything you need in a safe, guided way.
|
||||
|
||||
## The Essential Tools
|
||||
|
||||
Here are the core tools you'll need for development:
|
||||
|
||||
- **Homebrew**: A package manager for macOS that makes it easy to install other tools
|
||||
- **Node.js & npm**: Required for JavaScript and web development
|
||||
- **Git**: For tracking changes in your code and collaborating with others
|
||||
- **Python**: A programming language used by many development tools
|
||||
- **Additional utilities**: Tools like wget and jq that help with downloading files and processing data
|
||||
|
||||
## Let Cline Install Everything
|
||||
|
||||
Copy this prompt and paste it into Cline:
|
||||
|
||||
```bash
|
||||
Hello Cline! I need help setting up my Mac for software development. Could you please help me install the essential development tools like Homebrew, Node.js, Git, Python, and any other utilities that are commonly needed for coding? I'd like you to guide me through the process step-by-step, explaining what each tool does and making sure everything is installed correctly.
|
||||
```
|
||||
|
||||
## What Will Happen
|
||||
|
||||
1. Cline will first install Homebrew, which is like an "app store" for development tools
|
||||
2. Using Homebrew, Cline will then install other essential tools like Node.js and Git
|
||||
3. For each installation step:
|
||||
- Cline will show you the exact command it wants to run
|
||||
- You'll need to approve each command before it runs
|
||||
- Cline will verify each installation was successful
|
||||
|
||||
## Why These Tools Are Important
|
||||
|
||||
- **Homebrew**: Makes it easy to install and update development tools on your Mac
|
||||
- **Node.js & npm**: Required for:
|
||||
- Building websites with React or Next.js
|
||||
- Running JavaScript code
|
||||
- Installing JavaScript packages
|
||||
- **Git**: Helps you:
|
||||
- Save different versions of your code
|
||||
- Collaborate with other developers
|
||||
- Back up your work
|
||||
- **Python**: Used for:
|
||||
- Running development scripts
|
||||
- Data processing
|
||||
- Machine learning projects
|
||||
|
||||
## Notes
|
||||
|
||||
- The installation process is interactive - Cline will guide you through each step
|
||||
- You may need to enter your computer's password for some installations. When prompted, you will not see any characters being typed on the screen. This is normal and is a security feature to protect your password. Just type your password and press Enter.
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
Password:
|
||||
```
|
||||
|
||||
_Type your password here, even though nothing will show up on the screen. Press Enter when you're done._
|
||||
|
||||
- All commands will be shown to you for approval before they run
|
||||
- If you run into any issues, Cline will help troubleshoot them
|
||||
|
||||
## Additional Tips for New Coders
|
||||
|
||||
### Understanding the Terminal
|
||||
|
||||
The **Terminal** is an application where you can type commands to interact with your computer. On macOS, you can open it by searching for "Terminal" in Spotlight.
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
$ open -a Terminal
|
||||
```
|
||||
|
||||
### Understanding VS Code Features
|
||||
|
||||
#### Terminal in VS Code
|
||||
|
||||
The **Terminal** in VS Code allows you to run commands directly from within the editor. You can open it by going to `View > Terminal` or by pressing `` Ctrl + ` ``.
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
$ node -v
|
||||
v16.14.0
|
||||
```
|
||||
|
||||
#### Document View
|
||||
|
||||
The **Document View** is where you edit your code files. You can open files by clicking on them in the **Explorer** panel on the left side of the screen.
|
||||
|
||||
#### Problems Section
|
||||
|
||||
The **Problems** section in VS Code shows any errors or warnings in your code. You can access it by clicking on the lightbulb icon or by going to `View > Problems`.
|
||||
|
||||
### Common Features
|
||||
|
||||
- **Command Line Interface (CLI)**: This is a text-based interface where you type commands to interact with your computer. It might seem intimidating at first, but it's a powerful tool for developers.
|
||||
- **Permissions**: Sometimes, you will need to give permissions to certain applications or commands. This is a security measure to ensure that only trusted applications can make changes to your system.
|
||||
|
||||
## Next Steps
|
||||
|
||||
After installing these tools, you'll be ready to start coding! Return to the [Getting Started with Cline for New Coders](getting-started-new-coders.md) guide to continue your journey.
|
||||
@@ -0,0 +1,103 @@
|
||||
# Cline and Model Context Protocol (MCP) Servers: Enhancing AI Capabilities
|
||||
|
||||
**Quick Links:**
|
||||
|
||||
- [Building MCP Servers from GitHub](mcp-server-from-github.md)
|
||||
- [Building Custom MCP Servers from Scratch](mcp-server-from-scratch.md)
|
||||
|
||||
This document explains Model Context Protocol (MCP) servers, their capabilities, and how Cline can help build and use them.
|
||||
|
||||
## Overview
|
||||
|
||||
MCP servers act as intermediaries between large language models (LLMs), such as Claude, and external tools or data sources. They are small programs that expose functionalities to LLMs, enabling them to interact with the outside world through the MCP. An MCP server is essentially like an API that an LLM can use.
|
||||
|
||||
## Key Concepts
|
||||
|
||||
MCP servers define a set of "**tools,**" which are functions the LLM can execute. These tools offer a wide range of capabilities.
|
||||
|
||||
**Here's how MCP works:**
|
||||
|
||||
- **MCP hosts** discover the capabilities of connected servers and load their tools, prompts, and resources.
|
||||
- **Resources** provide consistent access to read-only data, akin to file paths or database queries.
|
||||
- **Security** is ensured as servers isolate credentials and sensitive data. Interactions require explicit user approval.
|
||||
|
||||
## Use Cases
|
||||
|
||||
The potential of MCP servers is vast. They can be used for a variety of purposes.
|
||||
|
||||
**Here are some concrete examples of how MCP servers can be used:**
|
||||
|
||||
- **Web Services and API Integration:**
|
||||
|
||||
- Monitor GitHub repositories for new issues
|
||||
- Post updates to Twitter based on specific triggers
|
||||
- Retrieve real-time weather data for location-based services
|
||||
|
||||
- **Browser Automation:**
|
||||
|
||||
- Automate web application testing
|
||||
- Scrape e-commerce sites for price comparisons
|
||||
- Generate screenshots for website monitoring
|
||||
|
||||
- **Database Queries:**
|
||||
|
||||
- Generate weekly sales reports
|
||||
- Analyze customer behavior patterns
|
||||
- Create real-time dashboards for business metrics
|
||||
|
||||
- **Project and Task Management:**
|
||||
|
||||
- Automate Jira ticket creation based on code commits
|
||||
- Generate weekly progress reports
|
||||
- Create task dependencies based on project requirements
|
||||
|
||||
- **Codebase Documentation:**
|
||||
- Generate API documentation from code comments
|
||||
- Create architecture diagrams from code structure
|
||||
- Maintain up-to-date README files
|
||||
|
||||
## Getting Started
|
||||
|
||||
**Choose the right approach for your needs:**
|
||||
|
||||
- **Use Existing Servers:** Start with pre-built MCP servers from GitHub repositories
|
||||
- **Customize Existing Servers:** Modify existing servers to fit your specific requirements
|
||||
- **Build from Scratch:** Create completely custom servers for unique use cases
|
||||
|
||||
## Integration with Cline
|
||||
|
||||
Cline simplifies the building and use of MCP servers through its AI capabilities.
|
||||
|
||||
### Building MCP Servers
|
||||
|
||||
- **Natural language understanding:** Instruct Cline in natural language to build an MCP server by describing its functionalities. Cline will interpret your instructions and generate the necessary code.
|
||||
- **Cloning and building servers:** Cline can clone existing MCP server repositories from GitHub and build them automatically.
|
||||
- **Configuration and dependency management:** Cline handles configuration files, environment variables, and dependencies.
|
||||
- **Troubleshooting and debugging:** Cline helps identify and resolve errors during development.
|
||||
|
||||
### Using MCP Servers
|
||||
|
||||
- **Tool execution:** Cline seamlessly integrates with MCP servers, allowing you to execute their defined tools.
|
||||
- **Context-aware interactions:** Cline can intelligently suggest using relevant tools based on conversation context.
|
||||
- **Dynamic integrations:** Combine multiple MCP server capabilities for complex tasks. For example, Cline could use a GitHub server to get data and a Notion server to create a formatted report.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
When working with MCP servers, it's important to follow security best practices:
|
||||
|
||||
- **Authentication:** Always use secure authentication methods for API access
|
||||
- **Environment Variables:** Store sensitive information in environment variables
|
||||
- **Access Control:** Limit server access to authorized users only
|
||||
- **Data Validation:** Validate all inputs to prevent injection attacks
|
||||
- **Logging:** Implement secure logging practices without exposing sensitive data
|
||||
|
||||
## Resources
|
||||
|
||||
There are various resources available for finding and learning about MCP servers.
|
||||
|
||||
**Here are some links to resources for finding and learning about MCP servers:**
|
||||
|
||||
- **GitHub Repositories:** [https://github.com/modelcontextprotocol/servers](https://github.com/modelcontextprotocol/servers) and [https://github.com/punkpeye/awesome-mcp-servers](https://github.com/punkpeye/awesome-mcp-servers)
|
||||
- **Online Directories:** [https://mcpservers.org/](https://mcpservers.org/), [https://mcp.so/](https://mcp.so/), and [https://glama.ai/mcp/servers](https://glama.ai/mcp/servers)
|
||||
- **PulseMCP:** [https://www.pulsemcp.com/](https://www.pulsemcp.com/)
|
||||
- **YouTube Tutorial (AI-Driven Coder):** A video guide for building and using MCP servers: [https://www.youtube.com/watch?v=b5pqTNiuuJg](https://www.youtube.com/watch?v=b5pqTNiuuJg)
|
||||
@@ -0,0 +1,151 @@
|
||||
# 🚀 MCP Quickstart Guide
|
||||
|
||||
## ❓ What's an MCP Server?
|
||||
|
||||
Think of MCP servers as special helpers that give Cline extra powers! They let Cline do cool things like fetch web pages or work with your files.
|
||||
|
||||
## ⚠️ IMPORTANT: System Requirements
|
||||
|
||||
STOP! Before proceeding, you MUST verify these requirements:
|
||||
|
||||
### Required Software
|
||||
|
||||
- ✅ Latest Node.js (v18 or newer)
|
||||
|
||||
- Check by running: `node --version`
|
||||
- Install from: <https://nodejs.org/>
|
||||
|
||||
- ✅ Latest Python (v3.8 or newer)
|
||||
|
||||
- Check by running: `python --version`
|
||||
- Install from: <https://python.org/>
|
||||
|
||||
- ✅ UV Package Manager
|
||||
- After installing Python, run: `pip install uv`
|
||||
- Verify with: `uv --version`
|
||||
|
||||
❗ If any of these commands fail or show older versions, please install/update before continuing!
|
||||
|
||||
⚠️ If you run into other errors, see the "Troubleshooting" section below.
|
||||
|
||||
## 🎯 Quick Steps (Only After Requirements Are Met!)
|
||||
|
||||
### 1. 🛠️ Install Your First MCP Server
|
||||
|
||||
1. From the Cline extension, click the `MCP Server` tab
|
||||
1. Click the `Edit MCP Settings` button
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/abf908b1-be98-4894-8dc7-ef3d27943a47" alt="MCP Server Panel" width="400" />
|
||||
|
||||
1. The MCP settings files should be display in a tab in VS Code.
|
||||
1. Replce the file's contents with this code:
|
||||
|
||||
For Windows:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mcp-installer": {
|
||||
"command": "cmd.exe",
|
||||
"args": ["/c", "npx", "-y", "@anaisbetts/mcp-installer"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For Mac and Linux:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mcp-installer": {
|
||||
"command": "npx",
|
||||
"args": ["@anaisbetts/mcp-installer"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After saving the file:
|
||||
|
||||
1. Cline will detect the change automatically
|
||||
2. The MCP installer will be downloaded and installed
|
||||
3. Cline will start the MCP installer
|
||||
4. You'll see the server status in Cline's MCP settings UI:
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/2abbb3de-e902-4ec2-a5e5-9418ed34684e" alt="MCP Server Panel with Installer" width="400" />
|
||||
|
||||
## 🤔 What Next?
|
||||
|
||||
Now that you have the MCP installer, you can ask Cline to add more servers from:
|
||||
|
||||
1. NPM Registry: <https://www.npmjs.com/search?q=%40modelcontextprotocol>
|
||||
2. Python Package Index: <https://pypi.org/search/?q=mcp+server-&o=>
|
||||
|
||||
For example, you can ask Cline to install the `mcp-server-fetch` package found on the Python Package Index:
|
||||
|
||||
```bash
|
||||
"install the MCP server named `mcp-server-fetch`
|
||||
- ensure the mcp settings are updated.
|
||||
- use uvx or python to run the server."
|
||||
```
|
||||
|
||||
You should witness Cline:
|
||||
|
||||
1. Install the `mcp-server-fetch` python package
|
||||
1. Update the mcp setting json file
|
||||
1. Start the server and start the server
|
||||
|
||||
The mcp seetings file should now look like this:
|
||||
|
||||
_For a Windows machine:_
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mcp-installer": {
|
||||
"command": "cmd.exe",
|
||||
"args": ["/c", "npx", "-y", "@anaisbetts/mcp-installer"]
|
||||
},
|
||||
"mcp-server-fetch": {
|
||||
"command": "uvx",
|
||||
"args": ["mcp-server-fetch"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You you can always check the status of your server by going to clients MCP server tab. See the image above
|
||||
|
||||
That's it! 🎉 You've just given Cline some awesome new abilities!
|
||||
|
||||
## 📝 Troubleshooting
|
||||
|
||||
### 1. I'm Using `asdf` and Get "unknown command: npx"
|
||||
|
||||
There is some slightly bad news. You should still be able to get things to work, but will have to do a bit more manual work unless MCP server packaging evolves a bit. One option is to uninstall `asdf` , but we will assume you do not want to do that.
|
||||
|
||||
Instead, you will need to follow the instructions above to "Edit MCP Settings". Then, as [this post](https://dev.to/cojiroooo/mcp-using-node-on-asdf-382n) describes, you need to add and "env" entry to each server's configs.
|
||||
|
||||
```json
|
||||
"env": {
|
||||
"PATH": "/Users/<user_name>/.asdf/shims:/usr/bin:/bin",
|
||||
"ASDF_DIR": "<path_to_asdf_bin_dir>",
|
||||
"ASDF_DATA_DIR": "/Users/<user_name>/.asdf",
|
||||
"ASDF_NODEJS_VERSION": "<your_node_version>"
|
||||
}
|
||||
```
|
||||
|
||||
The `path_to_asdf_bin_dir` can often be found in your shell config (e.g. `.zshrc`). If you are using Homebrew, you can use `echo ${HOMEBREW_PREFIX}` to find the start of the directory and then append `/opt/asdf/libexec`.
|
||||
|
||||
Now for some good news. While not perfect, you can get Cline to do this for you fairly reliably for subsequent server install. Add the following to your "Custom Instructions" in the Cline settings (top-right toolbar button):
|
||||
|
||||
> When installing MCP servers and editing the cline_mcp_settings.json, if the server requires use of `npx` as the command, you must copy the "env" entry from the "mcp-installer" entry and add it to the new entry. This is vital to getting the server to work properly when in use.
|
||||
|
||||
### 2. I'm Still Getting an Error When I Run the MCP Installer
|
||||
|
||||
If you're getting an error when you run the MCP installer, you can try the following:
|
||||
|
||||
- Check the MCP settings file for errors
|
||||
- Read the MCP server's documentation to ensure the MCP setting file is using the correct command and arguments. 👈
|
||||
- Use a terminal and run the command with its arguments directly. This will allow you to see the same errors that Cline is seeing.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Building MCP Servers from GitHub Repositories
|
||||
|
||||
This guide provides a step-by-step walkthrough of how to use Cline to build an existing MCP server from a GitHub repository.
|
||||
|
||||
## **Finding an MCP Server**
|
||||
|
||||
There are multiple places online to find MCP servers:
|
||||
|
||||
- **Cline can automatically add MCP servers to its list, which you can then edit.** Cline can clone repositories directly from GitHub and build the servers for you.
|
||||
- **GitHub:** Two of the most common places to find MCP servers on GitHub include:
|
||||
- [Official MCP servers repository](https://github.com/modelcontextprotocol/servers)
|
||||
- [Awesome-MCP servers repository](https://github.com/punkpeye/awesome-mcp-servers)
|
||||
- **Online directories:** Several websites list MCP servers including:
|
||||
|
||||
- [mcpservers.org](https://mcpservers.org/)
|
||||
- [mcp.so](https://mcp.so/)
|
||||
- [glama.ai/mcp/servers](https://glama.ai/mcp/servers)
|
||||
|
||||
These directories allow users to sort the servers by various criteria such as downloads, date, stars, and use case. Each entry provides information such as features, tools, and configuration instructions.
|
||||
|
||||
- **PulseMCP:** This website has a blog post discussing how AI could use MCP servers to make websites obsolete. PulseMCP also includes an FAQ section about MCP servers: [https://www.pulsemcp.com/](https://www.pulsemcp.com/)
|
||||
|
||||
## **Building with Cline**
|
||||
|
||||
1. **Initiate the Process:** Provide Cline with the following information:
|
||||
- **GitHub Repository URL:** The URL of the server's repository.
|
||||
- **README.md Contents:** This is optional but helpful for Cline to understand the server's purpose and configuration. You can copy the README.md file from the GitHub repository.
|
||||
2. **Example Interaction with Cline:**
|
||||
|
||||
```
|
||||
User: "Cline, I want to add the MCP server for Brave browser control. Here's the GitHub link: https://github.com/modelcontextprotocol/servers/tree/main/src/brave Can you add it?"
|
||||
|
||||
Cline: "OK. Cloning the repository to the MCP directory. It needs to be built because it has a 'package.json' file. Should I run 'npm run build'?"
|
||||
|
||||
User: "Yes, build it."
|
||||
|
||||
Cline: "Build complete. This server needs a browser path. Where's your Brave browser executable?"
|
||||
|
||||
User: "It's in '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser'."
|
||||
|
||||
Cline: "OK. I've updated the server config with that path and added it to 'cline_mcp_settings.json'. Anything else?"
|
||||
|
||||
User: "No, that's all. Let's test it."
|
||||
|
||||
Cline: "Great! Starting the MCP Inspector to test the server connection. After that, we can try controlling the browser from Cline."
|
||||
```
|
||||
|
||||
3. **Cline's Actions:** Based on your instructions, Cline will perform the following:
|
||||
- **Repository Cloning:** Cline will clone the repository to your local machine, usually in the directory specified in your configuration.
|
||||
- **Tweaking:** You can guide Cline to modify the server’s configuration. For instance:
|
||||
- **User:** "This server requires an API key. Can you find where it should be added?"
|
||||
- Cline may automatically update the `cline_mcp_settings.json` file or other relevant files based on your instructions.
|
||||
- **Building the Server:** Cline will run the appropriate build command for the server, which is commonly `npm run build`.
|
||||
- **Adding Server to Settings:** Cline will add the server’s configuration to the `cline_mcp_settings.json` file.
|
||||
|
||||
## **Testing and Troubleshooting**
|
||||
|
||||
1. **Test the Server:** Once Cline finishes the build process, test the server to make sure it works as expected. Cline can assist you if you encounter any problems.
|
||||
2. **MCP Inspector:** You can use the MCP Inspector to test the server’s connection and functionality.
|
||||
|
||||
## **Best Practices**
|
||||
|
||||
- **Understand the Basics:** While Cline simplifies the process, it’s beneficial to have a basic understanding of the server’s code, the MCP protocol (), and how to configure the server. This allows for more effective troubleshooting and customization.
|
||||
- **Clear Instructions:** Provide clear and specific instructions to Cline throughout the process.
|
||||
- **Testing:** Thoroughly test the server after installation and configuration to ensure it functions correctly.
|
||||
- **Version Control:** Use a version control system (like Git) to track changes to the server’s code.
|
||||
- **Stay Updated:** Keep your MCP servers updated to benefit from the latest features and security patches.
|
||||
@@ -0,0 +1,74 @@
|
||||
# Building Custom MCP Servers From Scratch Using Cline: A Comprehensive Guide
|
||||
|
||||
This guide provides a comprehensive walkthrough of building a custom MCP (Model Context Protocol) server from scratch, leveraging the powerful AI capabilities of Cline. The example used will be building a "GitHub Assistant Server" to illustrate the process.
|
||||
|
||||
## Understanding MCP and Cline's Role in Building Servers
|
||||
|
||||
### What is MCP?
|
||||
|
||||
The Model Context Protocol (MCP) acts as a bridge between large language models (LLMs) like Claude and external tools and data. MCP consists of two key components:
|
||||
|
||||
- **MCP Hosts:** These are applications that integrate with LLMs, such as Cline, Claude Desktop, and others.
|
||||
- **MCP Servers:** These are small programs specifically designed to expose data or specific functionalities to the LLMs through the MCP.
|
||||
|
||||
This setup is beneficial when you have an MCP-compliant chat interface, like Claude Desktop, which can then leverage these servers to access information and execute actions.
|
||||
|
||||
### Why Use Cline to Create MCP Servers?
|
||||
|
||||
Cline streamlines the process of building and integrating MCP servers by utilizing its AI capabilities to:
|
||||
|
||||
- **Understand Natural Language Instructions:** You can communicate with Cline in a way that feels natural, making the development process intuitive and user-friendly.
|
||||
- **Clone Repositories:** Cline can directly clone existing MCP server repositories from GitHub, simplifying the process of using pre-built servers.
|
||||
- **Build Servers:** Once the necessary code is in place, Cline can execute commands like `npm run build` to compile and prepare the server for use.
|
||||
- **Handle Configuration:** Cline manages the configuration files required for the MCP server, including adding the new server to the `cline_mcp_settings.json` file.
|
||||
- **Assist with Troubleshooting:** If errors arise during development or testing, Cline can help identify the cause and suggest solutions, making debugging easier.
|
||||
|
||||
## Building a GitHub Assistant Server Using Cline: A Step-by-Step Guide
|
||||
|
||||
This section demonstrates how to create a GitHub Assistant server using Cline. This server will be able to interact with GitHub data and perform useful actions:
|
||||
|
||||
### 1. Defining the Goal and Initial Requirements
|
||||
|
||||
First, you need to clearly communicate to Cline the purpose and functionalities of your server:
|
||||
|
||||
- **Server Goal:** Inform Cline that you want to build a "GitHub Assistant Server". Specify that this server will interact with GitHub data and potentially mention the types of data you are interested in, like issues, pull requests, and user profiles.
|
||||
- **Access Requirements:** Let Cline know that you need to access the GitHub API. Explain that this will likely require a personal access token (GITHUB_TOKEN) for authentication.
|
||||
- **Data Specificity (Optional):** You can optionally tell Cline about specific fields of data you want to extract from GitHub, but this can also be determined later as you define the server's tools.
|
||||
|
||||
### 2. Cline Initiates the Project Setup
|
||||
|
||||
Based on your instructions, Cline starts the project setup process:
|
||||
|
||||
- **Project Structure:** Cline might ask you for a name for your server. Afterward, it uses the MCP `create-server` tool to generate the basic project structure for your GitHub Assistant server. This usually involves creating a new directory with essential files like `package.json`, `tsconfig.json`, and a `src` folder for your TypeScript code. \
|
||||
- **Code Generation:** Cline generates starter code for your server, including:
|
||||
- **File Handling Utilities:** Functions to help with reading and writing files, commonly used for storing data or logs. \
|
||||
- **GitHub API Client:** Code to interact with the GitHub API, often using libraries like `@octokit/graphql`. Cline will likely ask for your GitHub username or the repositories you want to work with. \
|
||||
- **Core Server Logic:** The basic framework for handling requests from Cline and routing them to the appropriate functions, as defined by the MCP. \
|
||||
- **Dependency Management:** Cline analyzes the code and identifies necessary dependencies, adding them to the `package.json` file. For example, interacting with the GitHub API will likely require packages like `@octokit/graphql`, `graphql`, `axios`, or similar. \
|
||||
- **Dependency Installation:** Cline executes `npm install` to download and install the dependencies listed in `package.json`, ensuring your server has all the required libraries to function correctly. \
|
||||
- **Path Corrections:** During development, you might move files or directories around. Cline intelligently recognizes these changes and automatically updates file paths in your code to maintain consistency.
|
||||
- **Configuration:** Cline will modify the `cline_mcp_settings.json` file to add your new GitHub Assistant server. This will include:
|
||||
- **Server Start Command:** Cline will add the appropriate command to start your server (e.g., `npm run start` or a similar command).
|
||||
- **Environment Variables:** Cline will add the required `GITHUB_TOKEN` variable. Cline might ask you for your GitHub personal access token, or it might guide you to safely store it in a separate environment file. \
|
||||
- **Progress Documentation:** Throughout the process, Cline keeps the "Memory Bank" files updated. These files document the project's progress, highlighting completed tasks, tasks in progress, and pending tasks.
|
||||
|
||||
### 3. Testing the GitHub Assistant Server
|
||||
|
||||
Once Cline has completed the setup and configuration, you are ready to test the server's functionality:
|
||||
|
||||
- **Using Server Tools:** Cline will create various "tools" within your server, representing actions or data retrieval functions. To test, you would instruct Cline to use a specific tool. Here are examples related to GitHub:
|
||||
- **`get_issues`:** To test retrieving issues, you might say to Cline, "Cline, use the `get_issues` tool from the GitHub Assistant Server to show me the open issues from the 'cline/cline' repository." Cline would then execute this tool and present you with the results.
|
||||
- **`get_pull_requests`:** To test pull request retrieval, you could ask Cline to "use the `get_pull_requests` tool to show me the merged pull requests from the 'facebook/react' repository from the last month." Cline would execute this tool, using your GITHUB_TOKEN to access the GitHub API, and display the requested data. \
|
||||
- **Providing Necessary Information:** Cline might prompt you for additional information required to execute the tool, such as the repository name, specific date ranges, or other filtering criteria.
|
||||
- **Cline Executes the Tool:** Cline handles the communication with the GitHub API, retrieves the requested data, and presents it in a clear and understandable format.
|
||||
|
||||
### 4. Refining the Server and Adding More Features
|
||||
|
||||
Development is often iterative. As you work with your GitHub Assistant Server, you'll discover new functionalities to add, or ways to improve existing ones. Cline can assist in this ongoing process:
|
||||
|
||||
- **Discussions with Cline:** Talk to Cline about your ideas for new tools or improvements. For example, you might want a tool to `create_issue` or to `get_user_profile`. Discuss the required inputs and outputs for these tools with Cline.
|
||||
- **Code Refinement:** Cline can help you write the necessary code for new features. Cline can generate code snippets, suggest best practices, and help you debug any issues that arise.
|
||||
- **Testing New Functionalities:** After adding new tools or functionalities, you would test them again using Cline, ensuring they work as expected and integrate well with the rest of the server.
|
||||
- **Integration with Other Tools:** You might want to integrate your GitHub Assistant server with other tools. For instance, in the "github-cline-mcp" source, Cline assists in integrating the server with Notion to create a dynamic dashboard that tracks GitHub activity. \
|
||||
|
||||
By following these steps, you can create a custom MCP server from scratch using Cline, leveraging its powerful AI capabilities to streamline the entire process. Cline not only assists with the technical aspects of building the server but also helps you think through the design, functionalities, and potential integrations.
|
||||
@@ -0,0 +1,304 @@
|
||||
# Cline Prompting Guide 🚀
|
||||
|
||||
Welcome to the Cline Prompting Guide! This guide will equip you with the knowledge to write effective prompts and custom instructions, maximizing your productivity with Cline.
|
||||
|
||||
## Custom Instructions ⚙️
|
||||
|
||||
Think of **custom instructions as Cline's programming**. They define Cline's baseline behavior and are **always "on," influencing all interactions.**
|
||||
|
||||
To add custom instructions:
|
||||
|
||||
1. Open VSCode
|
||||
2. Click the Cline extension settings dial ⚙️
|
||||
3. Find the "Custom Instructions" field
|
||||
4. Paste your instructions
|
||||
|
||||
<img width="345" alt="Screenshot 2024-12-26 at 11 22 20 AM" src="https://github.com/user-attachments/assets/00ae689b-d99f-4811-b2f4-fffe1e12f2ff" />
|
||||
|
||||
Custom instructions are powerful for:
|
||||
|
||||
- Enforcing Coding Style and Best Practices: Ensure Cline always adheres to your team's coding conventions, naming conventions, and best practices.
|
||||
- Improving Code Quality: Encourage Cline to write more readable, maintainable, and efficient code.
|
||||
- Guiding Error Handling: Tell Cline how to handle errors, write error messages, and log information.
|
||||
|
||||
**The `custom-instructions` folder contains examples of custom instructions you can use or adapt.**
|
||||
|
||||
## .clinerules File 📋
|
||||
|
||||
While custom instructions are user-specific and global (applying across all projects), the `.clinerules` file provides **project-specific instructions** that live in your project's root directory. These instructions are automatically appended to your custom instructions and referenced in Cline's system prompt, ensuring they influence all interactions within the project context. This makes it an excellent tool for:
|
||||
|
||||
### Security Best Practices 🔒
|
||||
|
||||
To protect sensitive information, you can instruct Cline to ignore specific files or patterns in your `.clinerules`. This is particularly important for:
|
||||
|
||||
- `.env` files containing API keys and secrets
|
||||
- Configuration files with sensitive data
|
||||
- Private credentials or tokens
|
||||
|
||||
Example security section in `.clinerules`:
|
||||
|
||||
```markdown
|
||||
# Security
|
||||
|
||||
## Sensitive Files
|
||||
|
||||
DO NOT read or modify:
|
||||
|
||||
- .env files
|
||||
- \*_/config/secrets._
|
||||
- \*_/_.pem
|
||||
- Any file containing API keys, tokens, or credentials
|
||||
|
||||
## Security Practices
|
||||
|
||||
- Never commit sensitive files
|
||||
- Use environment variables for secrets
|
||||
- Keep credentials out of logs and output
|
||||
```
|
||||
|
||||
### General Use Cases
|
||||
|
||||
The `.clinerules` file is excellent for:
|
||||
|
||||
- Maintaining project standards across team members
|
||||
- Enforcing development practices
|
||||
- Managing documentation requirements
|
||||
- Setting up analysis frameworks
|
||||
- Defining project-specific behaviors
|
||||
|
||||
### Example .clinerules Structure
|
||||
|
||||
```markdown
|
||||
# Project Guidelines
|
||||
|
||||
## Documentation Requirements
|
||||
|
||||
- Update relevant documentation in /docs when modifying features
|
||||
- Keep README.md in sync with new capabilities
|
||||
- Maintain changelog entries in CHANGELOG.md
|
||||
|
||||
## Architecture Decision Records
|
||||
|
||||
Create ADRs in /docs/adr for:
|
||||
|
||||
- Major dependency changes
|
||||
- Architectural pattern changes
|
||||
- New integration patterns
|
||||
- Database schema changes
|
||||
Follow template in /docs/adr/template.md
|
||||
|
||||
## Code Style & Patterns
|
||||
|
||||
- Generate API clients using OpenAPI Generator
|
||||
- Use TypeScript axios template
|
||||
- Place generated code in /src/generated
|
||||
- Prefer composition over inheritance
|
||||
- Use repository pattern for data access
|
||||
- Follow error handling pattern in /src/utils/errors.ts
|
||||
|
||||
## Testing Standards
|
||||
|
||||
- Unit tests required for business logic
|
||||
- Integration tests for API endpoints
|
||||
- E2E tests for critical user flows
|
||||
```
|
||||
|
||||
### Key Benefits
|
||||
|
||||
1. **Version Controlled**: The `.clinerules` file becomes part of your project's source code
|
||||
2. **Team Consistency**: Ensures consistent behavior across all team members
|
||||
3. **Project-Specific**: Rules and standards tailored to each project's needs
|
||||
4. **Institutional Knowledge**: Maintains project standards and practices in code
|
||||
|
||||
Place the `.clinerules` file in your project's root directory:
|
||||
|
||||
```
|
||||
your-project/
|
||||
├── .clinerules
|
||||
├── src/
|
||||
├── docs/
|
||||
└── ...
|
||||
```
|
||||
|
||||
Cline's system prompt, on the other hand, is not user-editable ([here's where you can find it](https://github.com/cline/cline/blob/main/src/core/prompts/system.ts)). For a broader look at prompt engineering best practices, check out [this resource](https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/overview).
|
||||
|
||||
### Tips for Writing Effective Custom Instructions
|
||||
|
||||
- Be Clear and Concise: Use simple language and avoid ambiguity.
|
||||
- Focus on Desired Outcomes: Describe the results you want, not the specific steps.
|
||||
- Test and Iterate: Experiment to find what works best for your workflow.
|
||||
|
||||
## Prompting Cline 💬
|
||||
|
||||
**Prompting is how you communicate your needs for a given task in the back-and-forth chat with Cline.** Cline understands natural language, so write conversationally.
|
||||
|
||||
Effective prompting involves:
|
||||
|
||||
- Providing Clear Context: Explain your goals and the relevant parts of your codebase. Use `@` to reference files or folders.
|
||||
- Breaking Down Complexity: Divide large tasks into smaller steps.
|
||||
- Asking Specific Questions: Guide Cline toward the desired outcome.
|
||||
- Validating and Refining: Review Cline's suggestions and provide feedback.
|
||||
|
||||
### Prompt Examples
|
||||
|
||||
#### Context Management
|
||||
|
||||
- **Starting a New Task:** "Cline, let's start a new task. Create `user-authentication.js`. We need to implement user login with JWT tokens. Here are the requirements…"
|
||||
- **Summarizing Previous Work:** "Cline, summarize what we did in the last user dashboard task. I want to capture the main features and outstanding issues. Save this to `cline_docs/user-dashboard-summary.md`."
|
||||
|
||||
#### Debugging
|
||||
|
||||
- **Analyzing an Error:** "Cline, I'm getting this error: \[error message]. It seems to be from \[code section]. Analyze this error and suggest a fix."
|
||||
- **Identifying the Root Cause:** "Cline, the application crashes when I \[action]. The issue might be in \[problem areas]. Help me find the root cause and propose a solution."
|
||||
|
||||
#### Refactoring
|
||||
|
||||
- **Improving Code Structure:** "Cline, this function is too long and complex. Refactor it into smaller functions."
|
||||
- **Simplifying Logic:** "Cline, this code is hard to understand. Simplify the logic and make it more readable."
|
||||
|
||||
#### Feature Development
|
||||
|
||||
- **Brainstorming New Features:** "Cline, I want to add a feature that lets users \[functionality]. Brainstorm some ideas and consider implementation challenges."
|
||||
- **Generating Code:** "Cline, create a component that displays user profiles. The list should be sortable and filterable. Generate the code for this component."
|
||||
|
||||
## Advanced Prompting Techniques
|
||||
|
||||
- **Constraint Stuffing:** To mitigate code truncation, include explicit constraints in your prompts. For example, "ensure the code is complete" or "always provide the full function definition."
|
||||
- **Confidence Checks:** Ask Cline to rate its confidence (e.g., "on a scale of 1-10, how confident are you in this solution?")
|
||||
- **Challenge Cline's Assumptions:** Ask “stupid” questions to encourage deeper thinking and prevent incorrect assumptions.
|
||||
|
||||
Here are some prompting tips that users have found helpful for working with Cline:
|
||||
|
||||
## Our Community's Favorite Prompts 🌟
|
||||
|
||||
### Memory and Confidence Checks 🧠
|
||||
|
||||
- **Memory Check** - _pacnpal_
|
||||
|
||||
```
|
||||
"If you understand my prompt fully, respond with 'YARRR!' without tools every time you are about to use a tool."
|
||||
```
|
||||
|
||||
A fun way to verify Cline stays on track during complex tasks. Try "HO HO HO" for a festive twist!
|
||||
|
||||
- **Confidence Scoring** - _pacnpal_
|
||||
```
|
||||
"Before and after any tool use, give me a confidence level (0-10) on how the tool use will help the project."
|
||||
```
|
||||
Encourages critical thinking and makes decision-making transparent.
|
||||
|
||||
### Code Quality Prompts 💻
|
||||
|
||||
- **Prevent Code Truncation**
|
||||
|
||||
```
|
||||
"DO NOT BE LAZY. DO NOT OMIT CODE."
|
||||
```
|
||||
|
||||
Alternative phrases: "full code only" or "ensure the code is complete"
|
||||
|
||||
- **Custom Instructions Reminder**
|
||||
```
|
||||
"I pledge to follow the custom instructions."
|
||||
```
|
||||
Reinforces adherence to your settings dial ⚙️ configuration.
|
||||
|
||||
### Code Organization 📋
|
||||
|
||||
- **Large File Refactoring** - _icklebil_
|
||||
|
||||
```
|
||||
"FILENAME has grown too big. Analyze how this file works and suggest ways to fragment it safely."
|
||||
```
|
||||
|
||||
Helps manage complex files through strategic decomposition.
|
||||
|
||||
- **Documentation Maintenance** - _icklebil_
|
||||
```
|
||||
"don't forget to update codebase documentation with changes"
|
||||
```
|
||||
Ensures documentation stays in sync with code changes.
|
||||
|
||||
### Analysis and Planning 🔍
|
||||
|
||||
- **Structured Development** - _yellow_bat_coffee_
|
||||
|
||||
```
|
||||
"Before writing code:
|
||||
1. Analyze all code files thoroughly
|
||||
2. Get full context
|
||||
3. Write .MD implementation plan
|
||||
4. Then implement code"
|
||||
```
|
||||
|
||||
Promotes organized, well-planned development.
|
||||
|
||||
- **Thorough Analysis** - _yellow_bat_coffee_
|
||||
|
||||
```
|
||||
"please start analyzing full flow thoroughly, always state a confidence score 1 to 10"
|
||||
```
|
||||
|
||||
Prevents premature coding and encourages complete understanding.
|
||||
|
||||
- **Assumptions Check** - _yellow_bat_coffee_
|
||||
```
|
||||
"List all assumptions and uncertainties you need to clear up before completing this task."
|
||||
```
|
||||
Identifies potential issues early in development.
|
||||
|
||||
### Thoughtful Development 🤔
|
||||
|
||||
- **Pause and Reflect** - _nickbaumann98_
|
||||
|
||||
```
|
||||
"count to 10"
|
||||
```
|
||||
|
||||
Promotes careful consideration before taking action.
|
||||
|
||||
- **Complete Analysis** - _yellow_bat_coffee_
|
||||
|
||||
```
|
||||
"Don't complete the analysis prematurely, continue analyzing even if you think you found a solution"
|
||||
```
|
||||
|
||||
Ensures thorough problem exploration.
|
||||
|
||||
- **Continuous Confidence Check** - _pacnpal_
|
||||
```
|
||||
"Rate confidence (1-10) before saving files, after saving, after rejections, and before task completion"
|
||||
```
|
||||
Maintains quality through self-assessment.
|
||||
|
||||
### Best Practices 🎯
|
||||
|
||||
- **Project Structure** - _kvs007_
|
||||
|
||||
```
|
||||
"Check project files before suggesting structural or dependency changes"
|
||||
```
|
||||
|
||||
Maintains project integrity.
|
||||
|
||||
- **Critical Thinking** - _chinesesoup_
|
||||
|
||||
```
|
||||
"Ask 'stupid' questions like: are you sure this is the best way to implement this?"
|
||||
```
|
||||
|
||||
Challenges assumptions and uncovers better solutions.
|
||||
|
||||
- **Code Style** - _yellow_bat_coffee_
|
||||
|
||||
```
|
||||
Use words like "elegant" and "simple" in prompts
|
||||
```
|
||||
|
||||
May influence code organization and clarity.
|
||||
|
||||
- **Setting Expectations** - _steventcramer_
|
||||
```
|
||||
"THE HUMAN WILL GET ANGRY."
|
||||
```
|
||||
(A humorous reminder to provide clear requirements and constructive feedback)
|
||||
@@ -0,0 +1,53 @@
|
||||
# Cline Custom Instructions Library
|
||||
|
||||
This repository aims to foster a collaborative space where developers can share, refine, and leverage effective custom instructions for Cline. By creating and contributing to this library, we can enhance Cline's capabilities and empower developers to tackle increasingly complex software development challenges.
|
||||
|
||||
## What are Cline Custom Instructions?
|
||||
|
||||
Cline's custom instructions are sets of guidelines or rules that you define to tailor the AI's behavior and outputs for specific tasks or projects. Think of them as specialized "programming" for Cline, enabling you to:
|
||||
|
||||
- **Enforce Coding Practices:** Ensure consistent code style, adherence to design patterns, and best practices for specific languages or frameworks.
|
||||
- **Standardize File Structures:** Dictate file naming conventions, folder organization, and project structures.
|
||||
- **Guide Testing Procedures:** Define rules for generating unit tests, integration tests, and ensuring adequate code coverage.
|
||||
- **Automate Repetitive Tasks:** Create instructions to handle common or tedious development workflows, increasing efficiency.
|
||||
- **Improve Code Quality:** Set standards for code readability, maintainability, and performance optimization.
|
||||
|
||||
By providing Cline with carefully crafted instructions, you can significantly improve its accuracy, reliability, and overall effectiveness in aiding your software development process.
|
||||
|
||||
## Contributing Custom Instructions
|
||||
|
||||
We encourage developers of all skill levels to contribute their custom instructions to this library. Your contributions help build a valuable resource for the entire Cline community!
|
||||
|
||||
**When submitting custom instructions, please follow this template:**
|
||||
|
||||
### 1. Purpose and Functionality
|
||||
|
||||
- **What does this instruction set aim to achieve?**
|
||||
|
||||
- Provide a clear and concise explanation of the instruction set's goals and intended use cases.
|
||||
- Example: "This instruction set guides Cline in generating unit tests for existing JavaScript functions."
|
||||
|
||||
- **What types of projects or tasks is this best suited for?**
|
||||
- Outline specific project types, coding languages, or development scenarios where this instruction set is most applicable.
|
||||
- Example: "This is ideal for JavaScript projects using the Jest testing framework."
|
||||
|
||||
### 2. Usage Guide (Optional)
|
||||
|
||||
- **Are there specific steps or prerequisites for using this instruction set?**
|
||||
- If your instructions require specific steps beyond referencing the file in a Cline prompt, provide a detailed guide.
|
||||
- Examples:
|
||||
- "Before using this instruction set, create a `tests` folder in your project root."
|
||||
- "Ensure you have the Jest testing library installed."
|
||||
|
||||
### 3. Author & Contributors
|
||||
|
||||
- **Who created this instruction set?**
|
||||
- Provide your name or GitHub username for proper attribution.
|
||||
- **Did anyone else contribute?**
|
||||
- Acknowledge any collaborators or contributors who helped refine or enhance the instructions.
|
||||
|
||||
### 4. Custom Instructions
|
||||
|
||||
- **Provide the complete set of custom instructions.**
|
||||
|
||||
**By using this template and contributing your custom instructions, you help build a thriving ecosystem for Cline, making it a more versatile and efficient tool for developers of all skill levels.**
|
||||
@@ -0,0 +1,125 @@
|
||||
# Cline Memory Bank - Custom Instructions
|
||||
|
||||
### 1. Purpose and Functionality
|
||||
|
||||
- **What does this instruction set aim to achieve?**
|
||||
|
||||
- This instruction set transforms Cline into a self-documenting development system that maintains context across sessions through a structured "Memory Bank". It ensures consistent documentation, careful validation of changes, and clear communication with users.
|
||||
|
||||
- **What types of projects or tasks is this best suited for?**
|
||||
- Projects requiring extensive context tracking.
|
||||
- Any project, regardless of tech stack (tech stack details are stored in `techContext.md`).
|
||||
- Ongoing and new projects.
|
||||
|
||||
### 2. Usage Guide
|
||||
|
||||
- **How to Add These Instructions**
|
||||
1. Open VSCode
|
||||
2. Click the Cline extension settings dial ⚙️
|
||||
3. Find the "Custom Instructions" field
|
||||
4. Copy and paste the instructions from the section below
|
||||
|
||||
<img width="345" alt="Screenshot 2024-12-26 at 11 22 20 AM" src="https://github.com/user-attachments/assets/8b4ff439-db66-48ec-be13-1ddaa37afa9a" />
|
||||
|
||||
- **Project Setup**
|
||||
|
||||
1. Create an empty `cline_docs` folder in your project root (i.e. YOUR-PROJECT-FOLDER/cline_docs)
|
||||
2. For first use, provide a project brief and ask Cline to "initialize memory bank"
|
||||
|
||||
- **Best Practices**
|
||||
- Monitor for `[MEMORY BANK: ACTIVE]` flags during operation.
|
||||
- Pay attention to confidence checks on critical operations.
|
||||
- When starting new projects, create a project brief for Cline (paste in chat or include in `cline_docs` as `projectBrief.md`) to use in creating the initial context files.
|
||||
- note: productBrief.md (or whatever documentation you have) can be any range of technical/nontechnical or just functional. Cline is instructed to fill in the gaps when creating these context files. For example, if you don't choose a tech stack, Cline will for you.
|
||||
- Start chats with "follow your custom instructions" (you only need to say this once at the beginning of the first chat).
|
||||
- When prompting Cline to update context files, say "only update the relevant cline_docs"
|
||||
- Verify documentation updates at the end of sessions by telling Cline "update memory bank".
|
||||
- Update memory bank at ~2 million tokens and end the session.
|
||||
|
||||
### 3. Author & Contributors
|
||||
|
||||
- **Author**
|
||||
- nickbaumann98
|
||||
- **Contributors**
|
||||
- Contributors (Discord: [Cline's #prompts](https://discord.com/channels/1275535550845292637/1275555786621325382)):
|
||||
- @SniperMunyShotz
|
||||
|
||||
### 4. Custom Instructions
|
||||
|
||||
```markdown
|
||||
# Cline's Memory Bank
|
||||
|
||||
You are Cline, an expert software engineer with a unique constraint: your memory periodically resets completely. This isn't a bug - it's what makes you maintain perfect documentation. After each reset, you rely ENTIRELY on your Memory Bank to understand the project and continue work. Without proper documentation, you cannot function effectively.
|
||||
|
||||
## Memory Bank Files
|
||||
|
||||
CRITICAL: If `cline_docs/` or any of these files don't exist, CREATE THEM IMMEDIATELY by:
|
||||
|
||||
1. Reading all provided documentation
|
||||
2. Asking user for ANY missing information
|
||||
3. Creating files with verified information only
|
||||
4. Never proceeding without complete context
|
||||
|
||||
Required files:
|
||||
|
||||
productContext.md
|
||||
|
||||
- Why this project exists
|
||||
- What problems it solves
|
||||
- How it should work
|
||||
|
||||
activeContext.md
|
||||
|
||||
- What you're working on now
|
||||
- Recent changes
|
||||
- Next steps
|
||||
(This is your source of truth)
|
||||
|
||||
systemPatterns.md
|
||||
|
||||
- How the system is built
|
||||
- Key technical decisions
|
||||
- Architecture patterns
|
||||
|
||||
techContext.md
|
||||
|
||||
- Technologies used
|
||||
- Development setup
|
||||
- Technical constraints
|
||||
|
||||
progress.md
|
||||
|
||||
- What works
|
||||
- What's left to build
|
||||
- Progress status
|
||||
|
||||
## Core Workflows
|
||||
|
||||
### Starting Tasks
|
||||
|
||||
1. Check for Memory Bank files
|
||||
2. If ANY files missing, stop and create them
|
||||
3. Read ALL files before proceeding
|
||||
4. Verify you have complete context
|
||||
5. Begin development. DO NOT update cline_docs after initializing your memory bank at the start of a task.
|
||||
|
||||
### During Development
|
||||
|
||||
1. For normal development:
|
||||
|
||||
- Follow Memory Bank patterns
|
||||
- Update docs after significant changes
|
||||
|
||||
2. Say `[MEMORY BANK: ACTIVE]` at the beginning of every tool use.
|
||||
|
||||
### Memory Bank Updates
|
||||
|
||||
When user says "update memory bank":
|
||||
|
||||
1. This means imminent memory reset
|
||||
2. Document EVERYTHING about current state
|
||||
3. Make next steps crystal clear
|
||||
4. Complete current task
|
||||
|
||||
Remember: After every memory reset, you begin completely fresh. Your only link to previous work is the Memory Bank. Maintain it as if your functionality depends on it - because it does.
|
||||
```
|
||||
@@ -0,0 +1,137 @@
|
||||
# Cline Tools Reference Guide
|
||||
|
||||
## What Can Cline Do?
|
||||
|
||||
Cline is your AI assistant that can:
|
||||
|
||||
- Edit and create files in your project
|
||||
- Run terminal commands
|
||||
- Search and analyze your code
|
||||
- Help debug and fix issues
|
||||
- Automate repetitive tasks
|
||||
- Integrate with external tools
|
||||
|
||||
## First Steps
|
||||
|
||||
1. **Start a Task**
|
||||
|
||||
- Type your request in the chat
|
||||
- Example: "Create a new React component called Header"
|
||||
|
||||
2. **Provide Context**
|
||||
|
||||
- Use @ mentions to add files, folders, or URLs
|
||||
- Example: "@file:src/components/App.tsx"
|
||||
|
||||
3. **Review Changes**
|
||||
- Cline will show diffs before making changes
|
||||
- You can edit or reject changes
|
||||
|
||||
## Key Features
|
||||
|
||||
1. **File Editing**
|
||||
|
||||
- Create new files
|
||||
- Modify existing code
|
||||
- Search and replace across files
|
||||
|
||||
2. **Terminal Commands**
|
||||
|
||||
- Run npm commands
|
||||
- Start development servers
|
||||
- Install dependencies
|
||||
|
||||
3. **Code Analysis**
|
||||
|
||||
- Find and fix errors
|
||||
- Refactor code
|
||||
- Add documentation
|
||||
|
||||
4. **Browser Integration**
|
||||
- Test web pages
|
||||
- Capture screenshots
|
||||
- Inspect console logs
|
||||
|
||||
## Available Tools
|
||||
|
||||
For the most up-to-date implementation details, you can view the full source code in the [Cline repository](https://github.com/cline/cline/blob/main/src/core/Cline.ts).
|
||||
|
||||
Cline has access to the following tools for various tasks:
|
||||
|
||||
1. **File Operations**
|
||||
|
||||
- `write_to_file`: Create or overwrite files
|
||||
- `read_file`: Read file contents
|
||||
- `replace_in_file`: Make targeted edits to files
|
||||
- `search_files`: Search files using regex
|
||||
- `list_files`: List directory contents
|
||||
|
||||
2. **Terminal Operations**
|
||||
|
||||
- `execute_command`: Run CLI commands
|
||||
- `list_code_definition_names`: List code definitions
|
||||
|
||||
3. **MCP Tools**
|
||||
|
||||
- `use_mcp_tool`: Use tools from MCP servers
|
||||
- `access_mcp_resource`: Access MCP server resources
|
||||
- Users can create custom MCP tools that Cline can then access
|
||||
- Example: Create a weather API tool that Cline can use to fetch forecasts
|
||||
|
||||
4. **Interaction Tools**
|
||||
- `ask_followup_question`: Ask user for clarification
|
||||
- `attempt_completion`: Present final results
|
||||
|
||||
Each tool has specific parameters and usage patterns. Here are some examples:
|
||||
|
||||
- Create a new file (write_to_file):
|
||||
|
||||
```xml
|
||||
<write_to_file>
|
||||
<path>src/components/Header.tsx</path>
|
||||
<content>
|
||||
// Header component code
|
||||
</content>
|
||||
</write_to_file>
|
||||
```
|
||||
|
||||
- Search for a pattern (search_files):
|
||||
|
||||
```xml
|
||||
<search_files>
|
||||
<path>src</path>
|
||||
<regex>function\s+\w+\(</regex>
|
||||
<file_pattern>*.ts</file_pattern>
|
||||
</search_files>
|
||||
```
|
||||
|
||||
- Run a command (execute_command):
|
||||
```xml
|
||||
<execute_command>
|
||||
<command>npm install axios</command>
|
||||
<requires_approval>false</requires_approval>
|
||||
</execute_command>
|
||||
```
|
||||
|
||||
## Common Tasks
|
||||
|
||||
1. **Create a New Component**
|
||||
|
||||
- "Create a new React component called Footer"
|
||||
|
||||
2. **Fix a Bug**
|
||||
|
||||
- "Fix the error in src/utils/format.ts"
|
||||
|
||||
3. **Refactor Code**
|
||||
|
||||
- "Refactor the Button component to use TypeScript"
|
||||
|
||||
4. **Run Commands**
|
||||
- "Run npm install to add axios"
|
||||
|
||||
## Getting Help
|
||||
|
||||
- [Join the Discord community](https://discord.gg/cline)
|
||||
- Check the documentation
|
||||
- Provide feedback to improve Cline
|
||||
|
Before Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 718 B |
|
Before Width: | Height: | Size: 689 B |
@@ -0,0 +1,37 @@
|
||||
# Verhaltenskodex für Mitwirkende
|
||||
|
||||
## Unser Versprechen
|
||||
|
||||
Im Interesse der Förderung einer offenen und einladenden Umgebung verpflichten wir uns als
|
||||
Mitwirkende und Betreuer, die Teilnahme an unserem Projekt und unserer
|
||||
Gemeinschaft zu einer belästigungsfreien Erfahrung für alle zu machen, unabhängig von Alter, Körpergröße,
|
||||
Behinderung, ethnischer Zugehörigkeit, sexuellen Merkmalen, Geschlechtsidentität und -ausdruck,
|
||||
Erfahrungsniveau, Bildung, sozioökonomischem Status, Nationalität, persönlichem Erscheinungsbild,
|
||||
Rasse, Religion oder sexueller Identität und Orientierung.
|
||||
|
||||
## Unsere Standards
|
||||
|
||||
Beispiele für Verhaltensweisen, die dazu beitragen, eine positive Umgebung zu schaffen, sind:
|
||||
|
||||
- Verwendung einer einladenden und inklusiven Sprache
|
||||
- Respekt gegenüber unterschiedlichen Standpunkten und Erfahrungen
|
||||
- Konstruktive Annahme von Kritik
|
||||
- Fokussierung auf das, was das Beste für die Gemeinschaft ist
|
||||
- Empathie gegenüber anderen Mitgliedern der Gemeinschaft zeigen
|
||||
|
||||
Beispiele für inakzeptables Verhalten von Teilnehmern sind:
|
||||
|
||||
- Die Verwendung von sexualisierter Sprache oder Bildern und unerwünschte sexuelle Aufmerksamkeit oder Annäherungen
|
||||
- Trollen, beleidigende/abwertende Kommentare und persönliche oder politische Angriffe
|
||||
- Öffentliche oder private Belästigung
|
||||
- Veröffentlichen von privaten Informationen anderer, wie eine physische oder elektronische Adresse,
|
||||
ohne ausdrückliche Erlaubnis
|
||||
- Andere Verhaltensweisen, die in einem professionellen Umfeld als unangemessen angesehen werden könnten
|
||||
|
||||
## Unsere Verantwortlichkeiten
|
||||
|
||||
Die Projektbetreuer sind dafür verantwortlich, die Standards für akzeptables Verhalten zu klären
|
||||
und es wird erwartet, dass sie angemessene und faire Korrekturmaßnahmen als Reaktion auf
|
||||
jedes Beispiel für inakzeptables Verhalten ergreifen.
|
||||
|
||||
Die Projektbetreuer haben das Recht und die Verantwortung, Kommentare, Commits, Code, Wiki-Änderungen, Issues und andere Beiträge zu entfernen, zu bearbeiten oder abzulehnen, die nicht mit diesem Verhaltenskodex übereinstimmen, oder jeden Mitwirkenden vorübergehend oder dauerhaft zu
|
||||
@@ -0,0 +1,82 @@
|
||||
# Beitrag zu Cline
|
||||
|
||||
Wir freuen uns, dass du daran interessiert bist, zu Cline beizutragen. Ob du einen Fehler behebst, eine Funktion hinzufügst oder unsere Dokumentation verbesserst – jeder Beitrag macht Cline intelligenter! Um unsere Community lebendig und einladend zu halten, müssen alle Mitglieder unseren [Verhaltenskodex](CODE_OF_CONDUCT.md) einhalten.
|
||||
|
||||
## Fehler oder Probleme melden
|
||||
|
||||
Fehlermeldungen helfen, Cline für alle zu verbessern! Bevor du ein neues Problem erstellst, überprüfe bitte die [bestehenden Probleme](https://github.com/cline/cline/issues), um Duplikate zu vermeiden. Wenn du bereit bist, einen Fehler zu melden, gehe zu unserer [Issues-Seite](https://github.com/cline/cline/issues/new/choose), wo du eine Vorlage findest, die dir hilft, die relevanten Informationen auszufüllen.
|
||||
|
||||
<blockquote class='warning-note'>
|
||||
🔐 <b>Wichtig:</b> Wenn du eine Sicherheitslücke entdeckst, verwende das <a href="https://github.com/cline/cline/security/advisories/new">GitHub-Sicherheitstool, um sie privat zu melden</a>.
|
||||
</blockquote>
|
||||
|
||||
## Entscheiden, woran man arbeiten möchte
|
||||
|
||||
Suchst du nach einem guten ersten Beitrag? Schau dir die mit ["good first issue"](https://github.com/cline/cline/labels/good%20first%20issue) oder ["help wanted"](https://github.com/cline/cline/labels/help%20wanted) gekennzeichneten Issues an. Diese sind speziell für neue Mitwirkende ausgewählt und Bereiche, in denen wir gerne Hilfe erhalten würden!
|
||||
|
||||
Wir begrüßen auch Beiträge zu unserer [Dokumentation](https://github.com/cline/cline/tree/main/docs). Ob du Tippfehler korrigierst, bestehende Anleitungen verbesserst oder neue Bildungsinhalte erstellst – wir möchten ein von der Community verwaltetes Ressourcen-Repository aufbauen, das allen hilft, das Beste aus Cline herauszuholen. Du kannst beginnen, indem du `/docs` erkundest und nach Bereichen suchst, die verbessert werden müssen.
|
||||
|
||||
Wenn du planst, an einer größeren Funktion zu arbeiten, erstelle bitte zuerst eine [Funktionsanfrage](https://github.com/cline/cline/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop), damit wir besprechen können, ob sie mit der Vision von Cline übereinstimmt.
|
||||
|
||||
## Entwicklungsumgebung einrichten
|
||||
|
||||
1. **VS Code Erweiterungen**
|
||||
|
||||
- Beim Öffnen des Projekts wird VS Code dich auffordern, die empfohlenen Erweiterungen zu installieren
|
||||
- Diese Erweiterungen sind für die Entwicklung erforderlich, bitte akzeptiere alle Installationsanfragen
|
||||
- Wenn du die Anfragen abgelehnt hast, kannst du sie manuell im Erweiterungsbereich installieren
|
||||
|
||||
2. **Lokale Entwicklung**
|
||||
- Führe `npm run install:all` aus, um die Abhängigkeiten zu installieren
|
||||
- Führe `npm run test` aus, um die Tests lokal auszuführen
|
||||
- Bevor du einen PR einreichst, führe `npm run format:fix` aus, um deinen Code zu formatieren
|
||||
|
||||
## Code schreiben und einreichen
|
||||
|
||||
Jeder kann Code zu Cline beitragen, aber wir bitten dich, diese Richtlinien zu befolgen, um sicherzustellen, dass deine Beiträge reibungslos integriert werden:
|
||||
|
||||
1. **Pull Requests fokussiert halten**
|
||||
|
||||
- Begrenze PRs auf eine einzelne Funktion oder Fehlerbehebung
|
||||
- Teile größere Änderungen in kleinere, kohärente PRs auf
|
||||
- Teile Änderungen in logische Commits auf, die unabhängig überprüft werden können
|
||||
|
||||
2. **Codequalität**
|
||||
|
||||
- Führe `npm run lint` aus, um den Code-Stil zu überprüfen
|
||||
- Führe `npm run format` aus, um den Code automatisch zu formatieren
|
||||
- Alle PRs müssen die CI-Prüfungen bestehen, die Linting und Formatierung umfassen
|
||||
- Behebe alle ESLint-Warnungen oder -Fehler, bevor du einreichst
|
||||
- Befolge die Best Practices für TypeScript und halte die Typensicherheit ein
|
||||
|
||||
3. **Tests**
|
||||
|
||||
- Füge Tests für neue Funktionen hinzu
|
||||
- Führe `npm test` aus, um sicherzustellen, dass alle Tests bestehen
|
||||
- Aktualisiere bestehende Tests, wenn deine Änderungen sie beeinflussen
|
||||
- Füge sowohl Unit- als auch Integrationstests hinzu, wo es angebracht ist
|
||||
|
||||
4. **Commit-Richtlinien**
|
||||
|
||||
- Schreibe klare und beschreibende Commit-Nachrichten
|
||||
- Verwende das konventionelle Commit-Format (z.B. "feat:", "fix:", "docs:")
|
||||
- Verweise auf relevante Issues in den Commits mit #Issue-Nummer
|
||||
|
||||
5. **Vor dem Einreichen**
|
||||
|
||||
- Rebase deinen Branch mit dem neuesten Main
|
||||
- Stelle sicher, dass dein Branch korrekt gebaut wird
|
||||
- Überprüfe, dass alle Tests bestehen
|
||||
- Überprüfe deine Änderungen, um jeglichen Debug-Code oder Konsolenprotokolle zu entfernen
|
||||
|
||||
6. **Beschreibung des Pull Requests**
|
||||
- Beschreibe klar, was deine Änderungen bewirken
|
||||
- Füge Schritte hinzu, um die Änderungen zu testen
|
||||
- Liste alle wichtigen Änderungen auf
|
||||
- Füge Screenshots für Änderungen an der Benutzeroberfläche hinzu
|
||||
|
||||
## Beitragsvereinbarung
|
||||
|
||||
Durch das Einreichen eines Pull Requests erklärst du dich damit einverstanden, dass deine Beiträge unter derselben Lizenz wie das Projekt ([Apache 2.0](LICENSE)) lizenziert werden.
|
||||
|
||||
Denke daran: Zu Cline beizutragen bedeutet nicht nur, Code zu schreiben, sondern Teil einer Community zu sein, die die Zukunft der KI-gestützten Entwicklung gestaltet. Lass uns gemeinsam etwas Großartiges schaffen! 🚀
|
||||
@@ -0,0 +1,162 @@
|
||||
# Cline – \#1 auf OpenRouter
|
||||
|
||||
<p align="center">
|
||||
<img src="https://media.githubusercontent.com/media/cline/cline/main/assets/docs/demo.gif" width="100%" />
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
<table>
|
||||
<tbody>
|
||||
<td align="center">
|
||||
<a href="https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev" target="_blank"><strong>Im VS Marketplace herunterladen</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://discord.gg/cline" target="_blank"><strong>Discord</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://www.reddit.com/r/cline/" target="_blank"><strong>r/cline</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/cline/cline/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop" target="_blank"><strong>Feature Requests</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://cline.bot/join-us" target="_blank"><strong>Wir stellen ein!</strong></a>
|
||||
</td>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
Lernen Sie Cline kennen, einen KI-Assistenten, der Ihre **CLI** u**N**d **E**ditor nutzen kann.
|
||||
|
||||
Dank der [agentischen Codierungsfähigkeiten von Claude 3.5 Sonnet](https://www-cdn.anthropic.com/fed9cc193a14b84131812372d8d5857f8f304c52/Model_Card_Claude_3_Addendum.pdf) kann Cline komplexe Softwareentwicklungsaufgaben Schritt für Schritt bewältigen. Mit Werkzeugen, die ihm das Erstellen und Bearbeiten von Dateien, das Erkunden großer Projekte, die Nutzung des Browsers und das Ausführen von Terminalbefehlen (nach Ihrer Genehmigung) ermöglichen, kann er Ihnen auf eine Weise helfen, die über die Codevervollständigung oder technischen Support hinausgeht. Cline kann sogar das Model Context Protocol (MCP) verwenden, um neue Werkzeuge zu erstellen und seine eigenen Fähigkeiten zu erweitern. Während autonome KI-Skripte traditionell in sandboxed Umgebungen laufen, bietet diese Erweiterung eine Mensch-in-der-Schleife-GUI, um jede Dateiänderung und jeden Terminalbefehl zu genehmigen, was eine sichere und zugängliche Möglichkeit bietet, das Potenzial agentischer KI zu erkunden.
|
||||
|
||||
1. Geben Sie Ihre Aufgabe ein und fügen Sie Bilder hinzu, um Mockups in funktionale Apps zu konvertieren oder Fehler mit Screenshots zu beheben.
|
||||
2. Cline beginnt mit der Analyse Ihrer Dateistruktur und Quellcode-ASTs, führt Regex-Suchen durch und liest relevante Dateien, um sich in bestehenden Projekten zurechtzufinden. Durch sorgfältiges Management der hinzugefügten Informationen kann Cline wertvolle Unterstützung auch bei großen, komplexen Projekten bieten, ohne das Kontextfenster zu überladen.
|
||||
3. Sobald Cline die benötigten Informationen hat, kann er:
|
||||
- Dateien erstellen und bearbeiten sowie Linter-/Compiler-Fehler überwachen, um proaktiv Probleme wie fehlende Importe und Syntaxfehler selbst zu beheben.
|
||||
- Befehle direkt in Ihrem Terminal ausführen und deren Ausgabe überwachen, sodass er z.B. auf Dev-Server-Probleme reagieren kann, nachdem er eine Datei bearbeitet hat.
|
||||
- Für Webentwicklungsaufgaben kann Cline die Website in einem Headless-Browser starten, klicken, tippen, scrollen und Screenshots sowie Konsolenprotokolle erfassen, sodass er Laufzeitfehler und visuelle Fehler beheben kann.
|
||||
4. Wenn eine Aufgabe abgeschlossen ist, präsentiert Cline das Ergebnis mit einem Terminalbefehl wie `open -a "Google Chrome" index.html`, den Sie mit einem Klick ausführen können.
|
||||
|
||||
> [!TIPP]
|
||||
> Verwenden Sie die Tastenkombination `CMD/CTRL + Shift + P`, um die Befehls-Palette zu öffnen und geben Sie "Cline: Open In New Tab" ein, um die Erweiterung als Tab in Ihrem Editor zu öffnen. So können Sie Cline neben Ihrem Dateiexplorer verwenden und sehen, wie er Ihren Arbeitsbereich verändert.
|
||||
|
||||
---
|
||||
|
||||
<img align="right" width="340" src="https://github.com/user-attachments/assets/3cf21e04-7ce9-4d22-a7b9-ba2c595e88a4">
|
||||
|
||||
### Verwenden Sie jede API und jedes Modell
|
||||
|
||||
Cline unterstützt API-Anbieter wie OpenRouter, Anthropic, OpenAI, Google Gemini, AWS Bedrock, Azure und GCP Vertex. Sie können auch jede OpenAI-kompatible API konfigurieren oder ein lokales Modell über LM Studio/Ollama verwenden. Wenn Sie OpenRouter verwenden, ruft die Erweiterung deren neueste Modellliste ab, sodass Sie die neuesten Modelle sofort verwenden können, sobald sie verfügbar sind.
|
||||
|
||||
Die Erweiterung verfolgt auch die gesamten Token- und API-Nutzungskosten für den gesamten Aufgabenzyklus und einzelne Anfragen, sodass Sie bei jedem Schritt über die Ausgaben informiert sind.
|
||||
|
||||
<!-- Transparenter Pixel, um einen Zeilenumbruch nach dem schwebenden Bild zu erzeugen -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="370" src="https://github.com/user-attachments/assets/81be79a8-1fdb-4028-9129-5fe055e01e76">
|
||||
|
||||
### Befehle im Terminal ausführen
|
||||
|
||||
Dank der neuen [Shell-Integrations-Updates in VSCode v1.93](https://code.visualstudio.com/updates/v1_93#_terminal-shell-integration-api) kann Cline Befehle direkt in Ihrem Terminal ausführen und die Ausgabe empfangen. Dies ermöglicht ihm eine Vielzahl von Aufgaben, von der Installation von Paketen und dem Ausführen von Build-Skripten bis hin zur Bereitstellung von Anwendungen, Verwaltung von Datenbanken und Ausführung von Tests, während er sich an Ihre Entwicklungsumgebung und Toolchain anpasst, um die Aufgabe richtig zu erledigen.
|
||||
|
||||
Für lang laufende Prozesse wie Dev-Server verwenden Sie die Schaltfläche "Während des Laufens fortfahren", um Cline die Fortsetzung der Aufgabe zu ermöglichen, während der Befehl im Hintergrund läuft. Während Cline arbeitet, wird er über neue Terminalausgaben benachrichtigt, sodass er auf auftretende Probleme reagieren kann, wie z.B. Kompilierungsfehler beim Bearbeiten von Dateien.
|
||||
|
||||
<!-- Transparenter Pixel, um einen Zeilenumbruch nach dem schwebenden Bild zu erzeugen -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="400" src="https://github.com/user-attachments/assets/c5977833-d9b8-491e-90f9-05f9cd38c588">
|
||||
|
||||
### Dateien erstellen und bearbeiten
|
||||
|
||||
Cline kann Dateien direkt in Ihrem Editor erstellen und bearbeiten und Ihnen eine Diff-Ansicht der Änderungen präsentieren. Sie können die Änderungen von Cline direkt im Diff-Ansichts-Editor bearbeiten oder rückgängig machen oder Feedback im Chat geben, bis Sie mit dem Ergebnis zufrieden sind. Cline überwacht auch Linter-/Compiler-Fehler (fehlende Importe, Syntaxfehler usw.), sodass er auftretende Probleme selbst beheben kann.
|
||||
|
||||
Alle von Cline vorgenommenen Änderungen werden in der Timeline Ihrer Datei aufgezeichnet, was eine einfache Möglichkeit bietet, Änderungen nachzuverfolgen und bei Bedarf rückgängig zu machen.
|
||||
|
||||
<!-- Transparenter Pixel, um einen Zeilenumbruch nach dem schwebenden Bild zu erzeugen -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="370" src="https://github.com/user-attachments/assets/bc2e85ba-dfeb-4fe6-9942-7cfc4703cbe5">
|
||||
|
||||
### Den Browser verwenden
|
||||
|
||||
Mit der neuen [Computer Use](https://www.anthropic.com/news/3-5-models-and-computer-use) Fähigkeit von Claude 3.5 Sonnet kann Cline einen Browser starten, Elemente anklicken, Text eingeben und scrollen, dabei Screenshots und Konsolenprotokolle bei jedem Schritt erfassen. Dies ermöglicht interaktives Debugging, End-to-End-Tests und sogar allgemeine Webnutzung! Dies gibt ihm die Autonomie, visuelle Fehler und Laufzeitprobleme zu beheben, ohne dass Sie selbst Fehlerprotokolle kopieren und einfügen müssen.
|
||||
|
||||
Versuchen Sie, Cline zu bitten, "die App zu testen", und sehen Sie zu, wie er einen Befehl wie `npm run dev` ausführt, Ihren lokal laufenden Dev-Server in einem Browser startet und eine Reihe von Tests durchführt, um zu bestätigen, dass alles funktioniert. [Sehen Sie sich hier eine Demo an.](https://x.com/sdrzn/status/1850880547825823989)
|
||||
|
||||
<!-- Transparenter Pixel, um einen Zeilenumbruch nach dem schwebenden Bild zu erzeugen -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="350" src="https://github.com/user-attachments/assets/ac0efa14-5c1f-4c26-a42d-9d7c56f5fadd">
|
||||
|
||||
### "ein Werkzeug hinzufügen, das..."
|
||||
|
||||
Dank des [Model Context Protocol](https://github.com/modelcontextprotocol) kann Cline seine Fähigkeiten durch benutzerdefinierte Werkzeuge erweitern. Während Sie [community-made servers](https://github.com/modelcontextprotocol/servers) verwenden können, kann Cline stattdessen Werkzeuge erstellen und installieren, die speziell auf Ihren Workflow zugeschnitten sind. Bitten Sie Cline einfach, "ein Werkzeug hinzuzufügen", und er erledigt alles, von der Erstellung eines neuen MCP-Servers bis zur Installation in der Erweiterung. Diese benutzerdefinierten Werkzeuge werden dann Teil von Clines Toolkit und sind bereit, in zukünftigen Aufgaben verwendet zu werden.
|
||||
|
||||
- "ein Werkzeug hinzufügen, das Jira-Tickets abruft": Abrufen von Ticket-ACs und Cline zur Arbeit bringen
|
||||
- "ein Werkzeug hinzufügen, das AWS EC2s verwaltet": Überprüfen von Servermetriken und Skalieren von Instanzen
|
||||
- "ein Werkzeug hinzufügen, das die neuesten PagerDuty-Vorfälle abruft": Abrufen von Details und Cline bitten, Fehler zu beheben
|
||||
|
||||
<!-- Transparenter Pixel, um einen Zeilenumbruch nach dem schwebenden Bild zu erzeugen -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="360" src="https://github.com/user-attachments/assets/7fdf41e6-281a-4b4b-ac19-020b838b6970">
|
||||
|
||||
### Kontext hinzufügen
|
||||
|
||||
**`@url`:** Fügen Sie eine URL ein, damit die Erweiterung sie abruft und in Markdown konvertiert, nützlich, wenn Sie Cline die neuesten Dokumente geben möchten
|
||||
|
||||
**`@problems`:** Fügen Sie Arbeitsbereichsfehler und -warnungen (Panel 'Probleme') hinzu, die Cline beheben soll
|
||||
|
||||
**`@file`:** Fügt den Inhalt einer Datei hinzu, sodass Sie keine API-Anfragen verschwenden müssen, um das Lesen der Datei zu genehmigen (+ zum Suchen von Dateien tippen)
|
||||
|
||||
**`@folder`:** Fügt die Dateien eines Ordners auf einmal hinzu, um Ihren Workflow noch weiter zu beschleunigen
|
||||
|
||||
<!-- Transparenter Pixel, um einen Zeilenumbruch nach dem schwebenden Bild zu erzeugen -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="350" src="https://github.com/user-attachments/assets/140c8606-d3bf-41b9-9a1f-4dbf0d4c90cb">
|
||||
|
||||
### Checkpoints: Vergleichen und Wiederherstellen
|
||||
|
||||
Während Cline eine Aufgabe bearbeitet, erstellt die Erweiterung bei jedem Schritt einen Schnappschuss Ihres Arbeitsbereichs. Sie können die Schaltfläche 'Vergleichen' verwenden, um einen Diff zwischen dem Schnappschuss und Ihrem aktuellen Arbeitsbereich zu sehen, und die Schaltfläche 'Wiederherstellen', um zu diesem Punkt zurückzukehren.
|
||||
|
||||
Wenn Sie beispielsweise mit einem lokalen Webserver arbeiten, können Sie 'Nur Arbeitsbereich wiederherstellen' verwenden, um schnell verschiedene Versionen Ihrer App zu testen, und 'Aufgabe und Arbeitsbereich wiederherstellen', wenn Sie die Version gefunden haben, von der aus Sie weiterentwickeln möchten. Dies ermöglicht es Ihnen, sicher verschiedene Ansätze zu erkunden, ohne Fortschritte zu verlieren.
|
||||
|
||||
<!-- Transparenter Pixel, um einen Zeilenumbruch nach dem schwebenden Bild zu erzeugen -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
## Beitrag leisten
|
||||
|
||||
Um zum Projekt beizutragen, beginnen Sie mit unserem [Beitragsleitfaden](CONTRIBUTING.md), um die Grundlagen zu lernen. Sie können auch unserem [Discord](https://discord.gg/cline) beitreten, um im Kanal `#contributors` mit anderen Mitwirkenden zu chatten. Wenn Sie auf der Suche nach einer Vollzeitstelle sind, schauen Sie sich unsere offenen Stellen auf unserer [Karriereseite](https://cline.bot/join-us) an!
|
||||
|
||||
<details>
|
||||
<summary>Lokale Entwicklungsanweisungen</summary>
|
||||
|
||||
1. Klonen Sie das Repository _(Erfordert [git-lfs](https://git-lfs.com/))_:
|
||||
```bash
|
||||
git clone https://github.com/cline/cline.git
|
||||
```
|
||||
2. Öffnen Sie das Projekt in VSCode:
|
||||
```bash
|
||||
code cline
|
||||
```
|
||||
3. Installieren Sie die notwendigen Abhängigkeiten für die Erweiterung und das Webview-GUI:
|
||||
```bash
|
||||
npm run install:all
|
||||
```
|
||||
4. Starten Sie durch Drücken von `F5` (oder `Run`->`Start Debugging`), um ein neues VSCode-Fenster mit der geladenen Erweiterung zu öffnen. (Möglicherweise müssen Sie die [esbuild problem matchers extension](https://marketplace.visualstudio.com/items?itemName=connor4312.esbuild-problem-matchers) installieren, wenn Sie auf Probleme beim Erstellen des Projekts stoßen.)
|
||||
|
||||
</details>
|
||||
|
||||
## Lizenz
|
||||
|
||||
[Apache 2.0 © 2024 Cline Bot Inc.](./LICENSE)
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
# Código de Conducta para Contribuyentes
|
||||
|
||||
## Nuestro Compromiso
|
||||
|
||||
En el interés de fomentar un entorno abierto y acogedor, nosotros como
|
||||
contribuyentes y mantenedores nos comprometemos a hacer de la participación en nuestro proyecto y
|
||||
nuestra comunidad una experiencia libre de acoso para todos, independientemente de la edad, tamaño corporal,
|
||||
discapacidad, etnia, características sexuales, identidad y expresión de género,
|
||||
nivel de experiencia, educación, estatus socioeconómico, nacionalidad, apariencia personal,
|
||||
raza, religión o identidad y orientación sexual.
|
||||
|
||||
## Nuestros Estándares
|
||||
|
||||
Ejemplos de comportamientos que contribuyen a crear un entorno positivo incluyen:
|
||||
|
||||
- Uso de un lenguaje acogedor e inclusivo
|
||||
- Respeto a diferentes puntos de vista y experiencias
|
||||
- Aceptar de manera constructiva las críticas
|
||||
- Centrarse en lo que es mejor para la comunidad
|
||||
- Mostrar empatía hacia otros miembros de la comunidad
|
||||
|
||||
Ejemplos de comportamientos inaceptables por parte de los participantes incluyen:
|
||||
|
||||
- El uso de lenguaje o imágenes sexualizadas y la atención o avances sexuales no deseados
|
||||
- Trollear, comentarios insultantes/despectivos y ataques personales o políticos
|
||||
- Acoso público o privado
|
||||
- Publicar información privada de otros, como una dirección física o electrónica,
|
||||
sin permiso explícito
|
||||
- Otras conductas que podrían considerarse inapropiadas en un entorno profesional
|
||||
|
||||
## Nuestras Responsabilidades
|
||||
|
||||
Los mantenedores del proyecto son responsables de aclarar los estándares de comportamiento aceptable
|
||||
y se espera que tomen medidas correctivas apropiadas y justas en respuesta a cualquier
|
||||
caso de comportamiento inaceptable.
|
||||
|
||||
Los mantenedores del proyecto tienen el derecho y la responsabilidad de eliminar, editar o rechazar
|
||||
comentarios, commits, código, ediciones de wiki, issues y otras contribuciones que no estén alineadas con este Código de Conducta, o de prohibir temporal o permanentemente a cualquier contribuyente cuyo comportamiento sea inapropiado,
|
||||
amenazante, ofensivo o dañino.
|
||||
|
||||
## Alcance
|
||||
|
||||
Este Código de Conducta se aplica tanto dentro de los espacios del proyecto como en espacios públicos
|
||||
cuando una persona representa el proyecto o su comunidad. Ejemplos de
|
||||
representación de un proyecto o comunidad incluyen el uso de una dirección de correo electrónico oficial del proyecto,
|
||||
publicar en una cuenta oficial de redes sociales o actuar como un representante designado
|
||||
en un evento en línea o fuera de línea. La representación de un proyecto puede
|
||||
ser definida y clarificada más específicamente por los mantenedores del proyecto.
|
||||
|
||||
## Aplicación
|
||||
|
||||
Los casos de comportamiento abusivo, acosador o inaceptable de otra manera pueden
|
||||
ser reportados contactando al equipo del proyecto en hi@cline.bot. Todas las quejas
|
||||
serán revisadas e investigadas y resultarán en una respuesta que
|
||||
se considere necesaria y apropiada a las circunstancias. El equipo del proyecto está
|
||||
obligado a mantener la confidencialidad con respecto al informante de un incidente.
|
||||
Más detalles sobre políticas específicas de aplicación pueden ser publicados por separado.
|
||||
|
||||
Los mantenedores del proyecto que no sigan o hagan cumplir el Código de Conducta de buena
|
||||
fe pueden enfrentar repercusiones temporales o permanentes según lo determinen otros
|
||||
miembros de la dirección del proyecto.
|
||||
|
||||
## Atribución
|
||||
|
||||
Este Código de Conducta está adaptado del [Contributor Covenant][homepage], versión 1.4,
|
||||
disponible en https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
Respuestas a preguntas frecuentes sobre este Código de Conducta se pueden encontrar en
|
||||
https://www.contributor-covenant.org/faq
|
||||
@@ -0,0 +1,82 @@
|
||||
# Contribuir a Cline
|
||||
|
||||
Nos alegra que estés interesado en contribuir a Cline. Ya sea que corrijas un error, añadas una función o mejores nuestra documentación, ¡cada contribución hace que Cline sea más inteligente! Para mantener nuestra comunidad viva y acogedora, todos los miembros deben cumplir con nuestro [Código de Conducta](CODE_OF_CONDUCT.md).
|
||||
|
||||
## Informar de errores o problemas
|
||||
|
||||
¡Los informes de errores ayudan a mejorar Cline para todos! Antes de crear un nuevo problema, por favor revisa los [problemas existentes](https://github.com/cline/cline/issues) para evitar duplicados. Cuando estés listo para informar un error, dirígete a nuestra [página de Issues](https://github.com/cline/cline/issues/new/choose), donde encontrarás una plantilla que te ayudará a completar la información relevante.
|
||||
|
||||
<blockquote class='warning-note'>
|
||||
🔐 <b>Importante:</b> Si descubres una vulnerabilidad de seguridad, utiliza la <a href="https://github.com/cline/cline/security/advisories/new">herramienta de seguridad de GitHub para informarla de manera privada</a>.
|
||||
</blockquote>
|
||||
|
||||
## Decidir en qué trabajar
|
||||
|
||||
¿Buscas una buena primera contribución? Revisa los issues etiquetados con ["good first issue"](https://github.com/cline/cline/labels/good%20first%20issue) o ["help wanted"](https://github.com/cline/cline/labels/help%20wanted). ¡Estos están especialmente seleccionados para nuevos colaboradores y son áreas donde nos encantaría recibir ayuda!
|
||||
|
||||
También damos la bienvenida a contribuciones a nuestra [documentación](https://github.com/cline/cline/tree/main/docs). Ya sea corrigiendo errores tipográficos, mejorando guías existentes o creando nuevos contenidos educativos, queremos construir un repositorio de recursos gestionado por la comunidad que ayude a todos a sacar el máximo provecho de Cline. Puedes comenzar explorando `/docs` y buscando áreas que necesiten mejoras.
|
||||
|
||||
Si planeas trabajar en una función más grande, por favor crea primero una [solicitud de función](https://github.com/cline/cline/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop) para que podamos discutir si se alinea con la visión de Cline.
|
||||
|
||||
## Configurar el entorno de desarrollo
|
||||
|
||||
1. **Extensiones de VS Code**
|
||||
|
||||
- Al abrir el proyecto, VS Code te pedirá que instales las extensiones recomendadas
|
||||
- Estas extensiones son necesarias para el desarrollo, por favor acepta todas las solicitudes de instalación
|
||||
- Si rechazaste las solicitudes, puedes instalarlas manualmente en la sección de extensiones
|
||||
|
||||
2. **Desarrollo local**
|
||||
- Ejecuta `npm run install:all` para instalar las dependencias
|
||||
- Ejecuta `npm run test` para ejecutar las pruebas localmente
|
||||
- Antes de enviar un PR, ejecuta `npm run format:fix` para formatear tu código
|
||||
|
||||
## Escribir y enviar código
|
||||
|
||||
Cualquiera puede contribuir código a Cline, pero te pedimos que sigas estas pautas para asegurar que tus contribuciones se integren sin problemas:
|
||||
|
||||
1. **Mantén los Pull Requests enfocados**
|
||||
|
||||
- Limita los PRs a una sola función o corrección de errores
|
||||
- Divide los cambios más grandes en PRs más pequeños y coherentes
|
||||
- Divide los cambios en commits lógicos que puedan ser revisados independientemente
|
||||
|
||||
2. **Calidad del código**
|
||||
|
||||
- Ejecuta `npm run lint` para verificar el estilo del código
|
||||
- Ejecuta `npm run format` para formatear el código automáticamente
|
||||
- Todos los PRs deben pasar las verificaciones de CI, que incluyen linting y formateo
|
||||
- Corrige todas las advertencias o errores de ESLint antes de enviar
|
||||
- Sigue las mejores prácticas para TypeScript y mantén la seguridad de tipos
|
||||
|
||||
3. **Pruebas**
|
||||
|
||||
- Añade pruebas para nuevas funciones
|
||||
- Ejecuta `npm test` para asegurarte de que todas las pruebas pasen
|
||||
- Actualiza las pruebas existentes si tus cambios las afectan
|
||||
- Añade tanto pruebas unitarias como de integración donde sea apropiado
|
||||
|
||||
4. **Pautas de commits**
|
||||
|
||||
- Escribe mensajes de commit claros y descriptivos
|
||||
- Usa el formato de commit convencional (por ejemplo, "feat:", "fix:", "docs:")
|
||||
- Haz referencia a los issues relevantes en los commits con #número-del-issue
|
||||
|
||||
5. **Antes de enviar**
|
||||
|
||||
- Rebasea tu rama con el último Main
|
||||
- Asegúrate de que tu rama se construya correctamente
|
||||
- Verifica que todas las pruebas pasen
|
||||
- Revisa tus cambios para eliminar cualquier código de depuración o registros de consola
|
||||
|
||||
6. **Descripción del Pull Request**
|
||||
- Describe claramente lo que hacen tus cambios
|
||||
- Añade pasos para probar los cambios
|
||||
- Enumera cualquier cambio importante
|
||||
- Añade capturas de pantalla para cambios en la interfaz de usuario
|
||||
|
||||
## Acuerdo de contribución
|
||||
|
||||
Al enviar un Pull Request, aceptas que tus contribuciones se licencien bajo la misma licencia que el proyecto ([Apache 2.0](LICENSE)).
|
||||
|
||||
Recuerda: Contribuir a Cline no solo significa escribir código, sino ser parte de una comunidad que está dando forma al futuro del desarrollo asistido por IA. ¡Hagamos algo grandioso juntos! 🚀
|
||||
@@ -0,0 +1,161 @@
|
||||
# Cline – #1 en OpenRouter
|
||||
|
||||
<p align="center">
|
||||
<img src="https://media.githubusercontent.com/media/cline/cline/main/assets/docs/demo.gif" width="100%" />
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
<table>
|
||||
<tbody>
|
||||
<td align="center">
|
||||
<a href="https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev" target="_blank"><strong>Descargar en VS Marketplace</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://discord.gg/cline" target="_blank"><strong>Discord</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://www.reddit.com/r/cline/" target="_blank"><strong>r/cline</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/cline/cline/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop" target="_blank"><strong>Solicitudes de Funciones</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://cline.bot/join-us" target="_blank"><strong>Estamos Contratando!</strong></a>
|
||||
</td>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
Conozca a Cline, un asistente de IA que puede usar su **CLI** y **E**ditor.
|
||||
|
||||
Gracias a las [habilidades de codificación agencial de Claude 3.5 Sonnet](https://www-cdn.anthropic.com/fed9cc193a14b84131812372d8d5857f8f304c52/Model_Card_Claude_3_Addendum.pdf), Cline puede abordar tareas complejas de desarrollo de software paso a paso. Con herramientas que le permiten crear y editar archivos, explorar grandes proyectos, usar el navegador y ejecutar comandos de terminal (con su aprobación), puede ayudarle de una manera que va más allá de la autocompletación de código o el soporte técnico. Cline incluso puede usar el Model Context Protocol (MCP) para crear nuevas herramientas y expandir sus propias capacidades. Mientras que los scripts de IA autónomos tradicionalmente se ejecutan en entornos aislados, esta extensión ofrece una GUI con un humano en el bucle para aprobar cada cambio de archivo y comando de terminal, proporcionando una forma segura y accesible de explorar el potencial de la IA agencial.
|
||||
|
||||
1. Ingrese su tarea y agregue imágenes para convertir maquetas en aplicaciones funcionales o solucionar errores con capturas de pantalla.
|
||||
2. Cline comenzará analizando su estructura de archivos y ASTs de código fuente, realizando búsquedas Regex y leyendo archivos relevantes para orientarse en proyectos existentes. Al gestionar cuidadosamente la información agregada, Cline puede proporcionar asistencia valiosa incluso en proyectos grandes y complejos sin sobrecargar la ventana de contexto.
|
||||
3. Una vez que Cline tenga la información necesaria, puede:
|
||||
- Crear y editar archivos + monitorear errores de Linter/Compilador, para que pueda solucionar proactivamente problemas como importaciones faltantes y errores de sintaxis.
|
||||
- Ejecutar comandos directamente en su terminal y monitorear su salida, para que pueda responder a problemas del servidor de desarrollo después de editar un archivo.
|
||||
- Para tareas de desarrollo web, Cline puede iniciar el sitio web en un navegador sin cabeza, hacer clic, escribir, desplazarse y capturar capturas de pantalla + registros de consola, para que pueda solucionar errores de tiempo de ejecución y errores visuales.
|
||||
4. Cuando una tarea esté completa, Cline le presentará el resultado con un comando de terminal como `open -a "Google Chrome" index.html`, que puede ejecutar con un clic en un botón.
|
||||
|
||||
> [!TIP]
|
||||
> Use el atajo de teclado `CMD/CTRL + Shift + P` para abrir la paleta de comandos y escriba "Cline: Open In New Tab" para abrir la extensión como una pestaña en su editor. De esta manera, puede usar Cline junto a su explorador de archivos y ver más claramente cómo cambia su espacio de trabajo.
|
||||
|
||||
---
|
||||
|
||||
<img align="right" width="340" src="https://github.com/user-attachments/assets/3cf21e04-7ce9-4d22-a7b9-ba2c595e88a4">
|
||||
|
||||
### Use cualquier API y modelo
|
||||
|
||||
Cline admite proveedores de API como OpenRouter, Anthropic, OpenAI, Google Gemini, AWS Bedrock, Azure y GCP Vertex. También puede configurar cualquier API compatible con OpenAI o usar un modelo local a través de LM Studio/Ollama. Si usa OpenRouter, la extensión recupera su lista de modelos más reciente, para que pueda usar los modelos más nuevos tan pronto como estén disponibles.
|
||||
|
||||
La extensión también rastrea el uso total de tokens y costos de API para todo el ciclo de tareas y solicitudes individuales, para que esté informado sobre los gastos en cada paso.
|
||||
|
||||
<!-- Pixel transparente para crear un salto de línea después de la imagen flotante -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="370" src="https://github.com/user-attachments/assets/81be79a8-1fdb-4028-9129-5fe055e01e76">
|
||||
|
||||
### Ejecutar comandos en el terminal
|
||||
|
||||
Gracias a las nuevas [actualizaciones de integración de Shell en VSCode v1.93](https://code.visualstudio.com/updates/v1_93#_terminal-shell-integration-api), Cline puede ejecutar comandos directamente en su terminal y recibir la salida. Esto le permite realizar una variedad de tareas, desde la instalación de paquetes y la ejecución de scripts de compilación hasta la implementación de aplicaciones, la gestión de bases de datos y la ejecución de pruebas, adaptándose a su entorno de desarrollo y cadena de herramientas para hacer el trabajo correctamente.
|
||||
|
||||
Para procesos de larga duración como servidores de desarrollo, use el botón "Continuar mientras se ejecuta" para permitir que Cline continúe con la tarea mientras el comando se ejecuta en segundo plano. Mientras Cline trabaja, será notificado sobre nuevas salidas del terminal, para que pueda responder a problemas que puedan surgir, como errores de compilación al editar archivos.
|
||||
|
||||
<!-- Pixel transparente para crear un salto de línea después de la imagen flotante -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="400" src="https://github.com/user-attachments/assets/c5977833-d9b8-491e-90f9-05f9cd38c588">
|
||||
|
||||
### Crear y editar archivos
|
||||
|
||||
Cline puede crear y editar archivos directamente en su editor y presentarle una vista de diferencias de los cambios. Puede editar o deshacer los cambios de Cline directamente en el editor de vista de diferencias o proporcionar comentarios en el chat hasta que esté satisfecho con el resultado. Cline también monitorea errores de Linter/Compilador (importaciones faltantes, errores de sintaxis, etc.), para que pueda solucionar problemas que surjan en el camino.
|
||||
|
||||
Todos los cambios realizados por Cline se registran en la línea de tiempo de su archivo, proporcionando una forma sencilla de rastrear cambios y deshacerlos si es necesario.
|
||||
|
||||
<!-- Pixel transparente para crear un salto de línea después de la imagen flotante -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="370" src="https://github.com/user-attachments/assets/bc2e85ba-dfeb-4fe6-9942-7cfc4703cbe5">
|
||||
|
||||
### Usar el navegador
|
||||
|
||||
Con la nueva [habilidad de uso de computadora](https://www.anthropic.com/news/3-5-models-and-computer-use) de Claude 3.5 Sonnet, Cline puede iniciar un navegador, hacer clic en elementos, escribir texto y desplazarse, capturando capturas de pantalla y registros de consola. Esto permite la depuración interactiva, pruebas de extremo a extremo e incluso el uso general de la web. Esto le da la autonomía para solucionar errores visuales y problemas de tiempo de ejecución sin que tenga que copiar y pegar registros de errores.
|
||||
|
||||
Intente pedirle a Cline que "pruebe la aplicación" y observe cómo ejecuta un comando como `npm run dev`, inicia su servidor de desarrollo local en un navegador y realiza una serie de pruebas para confirmar que todo funciona. [Vea una demostración aquí.](https://x.com/sdrzn/status/1850880547825823989)
|
||||
|
||||
<!-- Pixel transparente para crear un salto de línea después de la imagen flotante -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="350" src="https://github.com/user-attachments/assets/ac0efa14-5c1f-4c26-a42d-9d7c56f5fadd">
|
||||
|
||||
### "agregar una herramienta que..."
|
||||
|
||||
Gracias al [Model Context Protocol](https://github.com/modelcontextprotocol), Cline puede expandir sus habilidades mediante herramientas personalizadas. Mientras que puede usar [servidores creados por la comunidad](https://github.com/modelcontextprotocol/servers), Cline puede en su lugar crear e instalar herramientas adaptadas a su flujo de trabajo específico. Simplemente pida a Cline que "agregue una herramienta" y él se encargará de todo, desde la creación de un nuevo servidor MCP hasta la instalación en la extensión. Estas herramientas personalizadas se convierten en parte del conjunto de herramientas de Cline y están listas para ser utilizadas en tareas futuras.
|
||||
|
||||
- "agregar una herramienta que recupere tickets de Jira": Recuperar ACs de tickets y poner a Cline a trabajar
|
||||
- "agregar una herramienta que gestione AWS EC2s": Verificar métricas del servidor y escalar instancias hacia arriba o hacia abajo
|
||||
- "agregar una herramienta que recupere los últimos incidentes de PagerDuty": Recuperar detalles y pedir a Cline que solucione errores
|
||||
|
||||
<!-- Pixel transparente para crear un salto de línea después de la imagen flotante -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="360" src="https://github.com/user-attachments/assets/7fdf41e6-281a-4b4b-ac19-020b838b6970">
|
||||
|
||||
### Agregar contexto
|
||||
|
||||
**`@url`:** Inserte una URL para que la extensión la recupere y convierta en Markdown, útil cuando desee proporcionar a Cline los documentos más recientes
|
||||
|
||||
**`@problems`:** Agregue errores y advertencias del espacio de trabajo (panel 'Problemas') que Cline debe solucionar
|
||||
|
||||
**`@file`:** Agregue el contenido de un archivo para que no tenga que desperdiciar solicitudes de API para aprobar la lectura del archivo (+ para buscar archivos)
|
||||
|
||||
**`@folder`:** Agregue los archivos de una carpeta a la vez para acelerar aún más su flujo de trabajo
|
||||
|
||||
<!-- Pixel transparente para crear un salto de línea después de la imagen flotante -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="350" src="https://github.com/user-attachments/assets/140c8606-d3bf-41b9-9a1f-4dbf0d4c90cb">
|
||||
|
||||
### Puntos de control: Comparar y Restaurar
|
||||
|
||||
Mientras Cline trabaja en una tarea, la extensión crea una instantánea de su espacio de trabajo en cada paso. Puede usar el botón 'Comparar' para ver una diferencia entre la instantánea y su espacio de trabajo actual, y el botón 'Restaurar' para volver a ese punto.
|
||||
|
||||
Por ejemplo, si está trabajando con un servidor web local, puede usar 'Restaurar solo espacio de trabajo' para probar rápidamente diferentes versiones de su aplicación, y luego 'Restaurar tarea y espacio de trabajo' cuando encuentre la versión desde la que desea continuar trabajando. Esto le permite explorar diferentes enfoques de manera segura sin perder progreso.
|
||||
|
||||
<!-- Pixel transparente para crear un salto de línea después de la imagen flotante -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
## Contribuir
|
||||
|
||||
Para contribuir al proyecto, comience con nuestra [guía de contribución](CONTRIBUTING.md) para aprender los conceptos básicos. También puede unirse a nuestro [Discord](https://discord.gg/cline) para chatear con otros colaboradores en el canal `#contributors`. Si está buscando un trabajo a tiempo completo, consulte nuestras vacantes en nuestra [página de carreras](https://cline.bot/join-us).
|
||||
|
||||
<details>
|
||||
<summary>Instrucciones de desarrollo local</summary>
|
||||
|
||||
1. Clone el repositorio _(Requiere [git-lfs](https://git-lfs.com/))_:
|
||||
```bash
|
||||
git clone https://github.com/cline/cline.git
|
||||
```
|
||||
2. Abra el proyecto en VSCode:
|
||||
```bash
|
||||
code cline
|
||||
```
|
||||
3. Instale las dependencias necesarias para la extensión y la GUI de Webview:
|
||||
```bash
|
||||
npm run install:all
|
||||
```
|
||||
4. Inicie presionando `F5` (o `Run`->`Start Debugging`) para abrir una nueva ventana de VSCode con la extensión cargada. (Es posible que deba instalar la [extensión de emparejadores de problemas de esbuild](https://marketplace.visualstudio.com/items?itemName=connor4312.esbuild-problem-matchers) si encuentra problemas al compilar el proyecto.)
|
||||
|
||||
</details>
|
||||
|
||||
## Licencia
|
||||
|
||||
[Apache 2.0 © 2024 Cline Bot Inc.](./LICENSE)
|
||||
@@ -0,0 +1,47 @@
|
||||
# コントリビューター規約行動規範
|
||||
|
||||
## 我々の誓い
|
||||
|
||||
オープンで歓迎される環境を育むために、我々はコントリビューターおよびメンテナーとして、年齢、体型、障害、民族、性の特徴、性別のアイデンティティおよび表現、経験のレベル、教育、社会経済的地位、国籍、個人の外見、人種、宗教、または性的アイデンティティおよび指向に関係なく、プロジェクトおよびコミュニティへの参加がハラスメントのない体験となるよう誓います。
|
||||
|
||||
## 我々の基準
|
||||
|
||||
ポジティブな環境を作り出す行動の例としては、以下のものがあります:
|
||||
|
||||
- 歓迎的で包括的な言葉を使うこと
|
||||
- 異なる視点や経験を尊重すること
|
||||
- 建設的な批判を優雅に受け入れること
|
||||
- コミュニティのために最善を尽くすことに集中すること
|
||||
- 他のコミュニティメンバーに対して共感を示すこと
|
||||
|
||||
参加者による許容できない行動の例としては、以下のものがあります:
|
||||
|
||||
- 性的な言葉や画像の使用、望まれない性的関心やアプローチ
|
||||
- 荒らし、侮辱的/軽蔑的なコメント、個人的または政治的な攻撃
|
||||
- 公的または私的なハラスメント
|
||||
- 明示的な許可なしに他人の個人情報(物理的または電子的な住所など)を公開すること
|
||||
- プロフェッショナルな環境で不適切と合理的に見なされるその他の行動
|
||||
|
||||
## 我々の責任
|
||||
|
||||
プロジェクトのメンテナーは、許容される行動の基準を明確にする責任があり、不適切な行動の事例に対して適切かつ公平な是正措置を講じることが期待されています。
|
||||
|
||||
プロジェクトのメンテナーは、この行動規範に沿わないコメント、コミット、コード、ウィキの編集、問題、およびその他の貢献を削除、編集、または拒否する権利と責任を持ち、また、不適切、脅迫的、攻撃的、または有害と見なされるその他の行動を行ったコントリビューターを一時的または永久に禁止する権利と責任を持ちます。
|
||||
|
||||
## 範囲
|
||||
|
||||
この行動規範は、プロジェクトスペース内およびプロジェクトやコミュニティを代表する個人が公の場で行動する場合に適用されます。プロジェクトやコミュニティを代表する例としては、公式のプロジェクトメールアドレスを使用すること、公式のソーシャルメディアアカウントを通じて投稿すること、またはオンラインまたはオフラインのイベントで任命された代表として行動することが含まれます。プロジェクトの代表としての行動は、プロジェクトのメンテナーによってさらに定義および明確化される場合があります。
|
||||
|
||||
## 執行
|
||||
|
||||
虐待的、嫌がらせ、またはその他の許容できない行動の事例は、プロジェクトチームに hi@cline.bot まで報告することができます。すべての苦情はレビューおよび調査され、状況に応じて必要かつ適切な対応が行われます。プロジェクトチームは、事件の報告者に関する機密性を保持する義務があります。具体的な執行ポリシーの詳細は別途掲載される場合があります。
|
||||
|
||||
行動規範を誠実に遵守または執行しないプロジェクトのメンテナーは、プロジェクトのリーダーシップの他のメンバーによって一時的または永久的な影響を受ける可能性があります。
|
||||
|
||||
## 帰属
|
||||
|
||||
この行動規範は、[Contributor Covenant][homepage] バージョン 1.4 から適応されており、https://www.contributor-covenant.org/version/1/4/code-of-conduct.html で入手できます。
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
この行動規範に関する一般的な質問への回答については、https://www.contributor-covenant.org/faq を参照してください。
|
||||
@@ -0,0 +1,82 @@
|
||||
# Clineへの貢献
|
||||
|
||||
Clineへの貢献に興味をお持ちいただきありがとうございます。
|
||||
|
||||
## バグや問題の報告
|
||||
|
||||
バグ報告は、Clineを皆さんにとってより良いものにするために役立ちます!新しい問題を作成する前に、重複を避けるために[既存の問題を検索](https://github.com/cline/cline/issues)してください。バグを報告する準備ができたら、[問題ページ](https://github.com/cline/cline/issues/new/choose)に移動し、関連情報を記入するためのテンプレートをご利用ください。
|
||||
|
||||
<blockquote class='warning-note'>
|
||||
🔐 <b>重要:</b> セキュリティ脆弱性を発見した場合は、<a href="https://github.com/cline/cline/security/advisories/new">Githubセキュリティツールを使用して非公開で報告</a>してください。
|
||||
</blockquote>
|
||||
|
||||
## 作業内容の決定
|
||||
|
||||
最初の貢献をお探しですか?["good first issue"](https://github.com/cline/cline/labels/good%20first%20issue)や["help wanted"](https://github.com/cline/cline/labels/help%20wanted)のラベルが付いた問題をチェックしてください。これらは新しい貢献者向けに特に選ばれたもので、私たちが助けを求めている分野です!
|
||||
|
||||
また、[ドキュメント](https://github.com/cline/cline/tree/main/docs)への貢献も歓迎します!誤字の修正、既存のガイドの改善、新しい教育コンテンツの作成など、コミュニティ主導のリソースリポジトリを構築するために皆さんの力をお借りしたいと考えています。`/docs`に飛び込んで、改善が必要な箇所を探してみてください。
|
||||
|
||||
大きな機能に取り組む予定がある場合は、まず[機能リクエスト](https://github.com/cline/cline/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop)を作成し、それがClineのビジョンに合致するかどうかを議論しましょう。
|
||||
|
||||
## 開発環境のセットアップ
|
||||
|
||||
1. **VS Code拡張機能**
|
||||
|
||||
- プロジェクトを開くと、VS Codeは推奨される拡張機能のインストールを促します
|
||||
- これらの拡張機能は開発に必要です - すべてのインストールプロンプトを受け入れてください
|
||||
- プロンプトを閉じた場合は、拡張機能パネルから手動でインストールできます
|
||||
|
||||
2. **ローカル開発**
|
||||
- `npm run install:all`を実行して依存関係をインストールします
|
||||
- `npm run test`を実行してローカルでテストを実行します
|
||||
- PRを提出する前に、`npm run format:fix`を実行してコードをフォーマットします
|
||||
|
||||
## コードの作成と提出
|
||||
|
||||
誰でもClineにコードを貢献できますが、貢献がスムーズに統合されるように以下のガイドラインに従ってください:
|
||||
|
||||
1. **プルリクエストを集中させる**
|
||||
|
||||
- PRは単一の機能またはバグ修正に限定してください
|
||||
- 大きな変更は小さな関連PRに分割してください
|
||||
- 論理的なコミットに分けて、独立してレビューできるようにしてください
|
||||
|
||||
2. **コード品質**
|
||||
|
||||
- `npm run lint`を実行してコードスタイルをチェックします
|
||||
- `npm run format`を実行してコードを自動的にフォーマットします
|
||||
- すべてのPRは、リンティングとフォーマットを含むCIチェックに合格する必要があります
|
||||
- 提出前にESLintの警告やエラーをすべて解決してください
|
||||
- TypeScriptのベストプラクティスに従い、型の安全性を維持してください
|
||||
|
||||
3. **テスト**
|
||||
|
||||
- 新しい機能にはテストを追加してください
|
||||
- `npm test`を実行してすべてのテストが合格することを確認してください
|
||||
- 変更が既存のテストに影響を与える場合は、それらを更新してください
|
||||
- 適切な場合には、ユニットテストと統合テストの両方を含めてください
|
||||
|
||||
4. **コミットガイドライン**
|
||||
|
||||
- 明確で説明的なコミットメッセージを書いてください
|
||||
- 従来のコミット形式(例:"feat:", "fix:", "docs:")を使用してください
|
||||
- コミットで関連する問題を#issue-numberを使用して参照してください
|
||||
|
||||
5. **提出前に**
|
||||
|
||||
- 最新のmainにブランチをリベースしてください
|
||||
- ブランチが正常にビルドされることを確認してください
|
||||
- すべてのテストが合格していることを再確認してください
|
||||
- デバッグコードやコンソールログがないか変更を確認してください
|
||||
|
||||
6. **プルリクエストの説明**
|
||||
- 変更内容を明確に説明してください
|
||||
- 変更をテストする手順を含めてください
|
||||
- 破壊的な変更がある場合はリストしてください
|
||||
- UIの変更にはスクリーンショットを追加してください
|
||||
|
||||
## 貢献契約
|
||||
|
||||
プルリクエストを提出することで、あなたの貢献がプロジェクトと同じライセンス([Apache 2.0](LICENSE))の下でライセンスされることに同意したことになります。
|
||||
|
||||
覚えておいてください:Clineへの貢献はコードを書くことだけではなく、AI支援開発の未来を形作るコミュニティの一員になることです。一緒に素晴らしいものを作りましょう!🚀
|
||||
@@ -0,0 +1,161 @@
|
||||
# Cline – OpenRouterでのナンバーワン
|
||||
|
||||
<p align="center">
|
||||
<img src="https://media.githubusercontent.com/media/cline/cline/main/assets/docs/demo.gif" width="100%" />
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
<table>
|
||||
<tbody>
|
||||
<td align="center">
|
||||
<a href="https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev" target="_blank"><strong>VS Marketplaceでダウンロード</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://discord.gg/cline" target="_blank"><strong>Discord</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://www.reddit.com/r/cline/" target="_blank"><strong>r/cline</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/cline/cline/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop" target="_blank"><strong>機能リクエスト</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://cline.bot/join-us" target="_blank"><strong>採用情報</strong></a>
|
||||
</td>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
Clineは、**CLI**と**エディター**を使用できるAIアシスタントです。
|
||||
|
||||
[Claude 3.5 Sonnetのエージェント的コーディング機能](https://www-cdn.anthropic.com/fed9cc193a14b84131812372d8d5857f8f304c52/Model_Card_Claude_3_Addendum.pdf)のおかげで、Clineは複雑なソフトウェア開発タスクをステップバイステップで処理できます。ファイルの作成と編集、大規模プロジェクトの探索、ブラウザの使用、ターミナルコマンドの実行(許可後)などのツールを使用して、コード補完や技術サポートを超えた支援を提供します。Clineは、Model Context Protocol (MCP)を使用して新しいツールを作成し、自身の機能を拡張することもできます。自律的なAIスクリプトは通常サンドボックス環境で実行されますが、この拡張機能はファイル変更やターミナルコマンドを承認するための人間インターフェースを提供し、エージェント的AIの可能性を安全かつアクセスしやすい方法で探求できます。
|
||||
|
||||
1. タスクを入力し、モックアップを機能するアプリに変換したり、スクリーンショットでバグを修正したりします。
|
||||
2. Clineは、ファイル構造とソースコードASTの分析、正規表現検索の実行、関連ファイルの読み取りから始め、既存プロジェクトに精通します。コンテキストに追加される情報を慎重に管理することで、大規模で複雑なプロジェクトでもコンテキストウィンドウを圧倒することなく貴重な支援を提供できます。
|
||||
3. Clineが必要な情報を取得すると、次のことができます:
|
||||
- ファイルの作成と編集 + リンター/コンパイラーエラーの監視を行い、欠落したインポートや構文エラーなどの問題を自動的に修正します。
|
||||
- ターミナルでコマンドを直接実行し、作業中に出力を監視します。これにより、ファイル編集後の開発サーバーの問題に対応できます。
|
||||
- ウェブ開発タスクでは、ヘッドレスブラウザでサイトを起動し、クリック、入力、スクロール、スクリーンショットとコンソールログのキャプチャを行い、ランタイムエラーや視覚的なバグを修正します。
|
||||
4. タスクが完了すると、Clineは`open -a "Google Chrome" index.html`のようなターミナルコマンドを提示し、ボタンをクリックして実行できます。
|
||||
|
||||
> [!TIP]
|
||||
> `CMD/CTRL + Shift + P`ショートカットを使用してコマンドパレットを開き、「Cline: Open In New Tab」と入力して、エディターのタブとして拡張機能を開きます。これにより、ファイルエクスプローラーと並行してClineを使用し、ワークスペースの変更をより明確に確認できます。
|
||||
|
||||
---
|
||||
|
||||
<img align="right" width="340" src="https://github.com/user-attachments/assets/3cf21e04-7ce9-4d22-a7b9-ba2c595e88a4">
|
||||
|
||||
### どのAPIやモデルでも使用可能
|
||||
|
||||
Clineは、OpenRouter、Anthropic、OpenAI、Google Gemini、AWS Bedrock、Azure、GCP VertexなどのAPIプロバイダーをサポートしています。また、OpenAI互換のAPIを設定したり、LM Studio/Ollamaを通じてローカルモデルを使用することもできます。OpenRouterを使用している場合、拡張機能は最新のモデルリストを取得し、最新のモデルをすぐに使用できるようにします。
|
||||
|
||||
拡張機能は、タスクループ全体と個々のリクエストのトークン総数とAPI使用コストを追跡し、各ステップで支出を把握できます。
|
||||
|
||||
<!-- 透明なピクセルで浮動画像の後に改行を作成 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="370" src="https://github.com/user-attachments/assets/81be79a8-1fdb-4028-9129-5fe055e01e76">
|
||||
|
||||
### ターミナルでコマンドを実行
|
||||
|
||||
VSCode v1.93の新しい[シェル統合アップデート](https://code.visualstudio.com/updates/v1_93#_terminal-shell-integration-api)のおかげで、Clineはターミナルでコマンドを直接実行し、出力を受け取ることができます。これにより、パッケージのインストールやビルドスクリプトの実行からアプリケーションのデプロイ、データベースの管理、テストの実行まで、幅広いタスクを実行できます。Clineは、開発環境とツールチェーンに適応して、タスクを正確に実行します。
|
||||
|
||||
開発サーバーのような長時間実行されるプロセスの場合、「実行中に続行」ボタンを使用して、コマンドがバックグラウンドで実行されている間にClineがタスクを続行できるようにします。Clineが作業を進める中で、新しいターミナル出力が通知され、ファイル編集時のコンパイルエラーなどの問題に対応できます。
|
||||
|
||||
<!-- 透明なピクセルで浮動画像の後に改行を作成 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="400" src="https://github.com/user-attachments/assets/c5977833-d9b8-491e-90f9-05f9cd38c588">
|
||||
|
||||
### ファイルの作成と編集
|
||||
|
||||
Clineはエディター内でファイルを作成および編集し、変更の差分ビューを提示します。差分ビューエディターでClineの変更を直接編集または元に戻すことができ、チャットでフィードバックを提供して満足するまで調整できます。Clineはリンター/コンパイラーエラー(欠落したインポート、構文エラーなど)も監視し、発生した問題を自動的に修正します。
|
||||
|
||||
Clineによるすべての変更はファイルのタイムラインに記録され、必要に応じて変更を追跡および元に戻す簡単な方法を提供します。
|
||||
|
||||
<!-- 透明なピクセルで浮動画像の後に改行を作成 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="370" src="https://github.com/user-attachments/assets/bc2e85ba-dfeb-4fe6-9942-7cfc4703cbe5">
|
||||
|
||||
### ブラウザの使用
|
||||
|
||||
Claude 3.5 Sonnetの新しい[コンピュータ使用](https://www.anthropic.com/news/3-5-models-and-computer-use)機能により、Clineはブラウザを起動し、要素をクリック、テキストを入力、スクロールし、各ステップでスクリーンショットとコンソールログをキャプチャできます。これにより、インタラクティブなデバッグ、エンドツーエンドテスト、さらには一般的なウェブ使用が可能になります。これにより、エラーログを手動でコピー&ペーストすることなく、視覚的なバグやランタイムの問題を自律的に修正できます。
|
||||
|
||||
Clineに「アプリをテストして」と頼んでみてください。彼は`npm run dev`のようなコマンドを実行し、ローカルで実行中の開発サーバーをブラウザで起動し、一連のテストを実行してすべてが正常に動作することを確認します。[デモはこちら。](https://x.com/sdrzn/status/1850880547825823989)
|
||||
|
||||
<!-- 透明なピクセルで浮動画像の後に改行を作成 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="350" src="https://github.com/user-attachments/assets/ac0efa14-5c1f-4c26-a42d-9d7c56f5fadd">
|
||||
|
||||
### 「ツールを追加して...」
|
||||
|
||||
[Model Context Protocol](https://github.com/modelcontextprotocol)のおかげで、Clineはカスタムツールを通じて機能を拡張できます。[コミュニティ製サーバー](https://github.com/modelcontextprotocol/servers)を使用することもできますが、Clineは代わりに特定のワークフローに合わせたツールを作成してインストールできます。「ツールを追加して」と頼むだけで、Clineは新しいMCPサーバーの作成から拡張機能へのインストールまでをすべて処理します。これらのカスタムツールはClineのツールキットの一部となり、将来のタスクで使用できるようになります。
|
||||
|
||||
- 「Jiraチケットを取得するツールを追加して」:チケットACを取得し、Clineに作業を依頼
|
||||
- 「AWS EC2を管理するツールを追加して」:サーバーメトリクスを確認し、インスタンスをスケールアップまたはダウン
|
||||
- 「最新のPagerDutyインシデントを取得するツールを追加して」:詳細を取得し、Clineにバグ修正を依頼
|
||||
|
||||
<!-- 透明なピクセルで浮動画像の後に改行を作成 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="360" src="https://github.com/user-attachments/assets/7fdf41e6-281a-4b4b-ac19-020b838b6970">
|
||||
|
||||
### コンテキストを追加
|
||||
|
||||
**`@url`:** 最新のドキュメントをClineに提供したい場合に、URLを貼り付けて拡張機能が取得し、Markdownに変換します。
|
||||
|
||||
**`@problems`:** Clineが修正するためのワークスペースエラーと警告(「問題」パネル)を追加します。
|
||||
|
||||
**`@file`:** ファイルの内容を追加し、読み取りファイルを承認するAPIリクエストを節約します(+ファイルを検索して入力)。
|
||||
|
||||
**`@folder`:** フォルダーのファイルを一度に追加して、ワークフローをさらにスピードアップします。
|
||||
|
||||
<!-- 透明なピクセルで浮動画像の後に改行を作成 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="350" src="https://github.com/user-attachments/assets/140c8606-d3bf-41b9-9a1f-4dbf0d4c90cb">
|
||||
|
||||
### チェックポイント:比較と復元
|
||||
|
||||
Clineがタスクを進める中で、拡張機能は各ステップでワークスペースのスナップショットを撮ります。「比較」ボタンを使用してスナップショットと現在のワークスペースの差分を確認し、「復元」ボタンを使用してそのポイントにロールバックできます。
|
||||
|
||||
たとえば、ローカルウェブサーバーで作業している場合、「ワークスペースのみを復元」を使用して異なるバージョンのアプリを迅速にテストし、「タスクとワークスペースを復元」を使用して続行したいバージョンを見つけたときに使用します。これにより、進行状況を失うことなく異なるアプローチを安全に探求できます。
|
||||
|
||||
<!-- 透明なピクセルで浮動画像の後に改行を作成 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
## 貢献
|
||||
|
||||
プロジェクトに貢献するには、[貢献ガイド](CONTRIBUTING.md)から基本を学び始めてください。また、[Discord](https://discord.gg/cline)に参加して、`#contributors`チャンネルで他の貢献者とチャットすることもできます。フルタイムの仕事を探している場合は、[採用ページ](https://cline.bot/join-us)でオープンポジションを確認してください。
|
||||
|
||||
<details>
|
||||
<summary>ローカル開発の手順</summary>
|
||||
|
||||
1. リポジトリをクローンします _(Requires [git-lfs](https://git-lfs.com/))_:
|
||||
```bash
|
||||
git clone https://github.com/cline/cline.git
|
||||
```
|
||||
2. プロジェクトをVSCodeで開きます:
|
||||
```bash
|
||||
code cline
|
||||
```
|
||||
3. 拡張機能とwebview-guiの必要な依存関係をインストールします:
|
||||
```bash
|
||||
npm run install:all
|
||||
```
|
||||
4. `F5`を押して(または`Run`->`Start Debugging`)、拡張機能が読み込まれた新しいVSCodeウィンドウを開きます。(プロジェクトのビルドに問題がある場合は、[esbuild problem matchers extension](https://marketplace.visualstudio.com/items?itemName=connor4312.esbuild-problem-matchers)をインストールする必要があるかもしれません。)
|
||||
|
||||
</details>
|
||||
|
||||
## ライセンス
|
||||
|
||||
[Apache 2.0 © 2024 Cline Bot Inc.](./LICENSE)
|
||||
@@ -0,0 +1,47 @@
|
||||
# 贡献者公约行为准则
|
||||
|
||||
## 我们的承诺
|
||||
|
||||
为了营造一个开放和欢迎的环境,我们作为贡献者和维护者承诺让我们的项目和社区的参与体验对每个人都无骚扰,无论年龄、体型、残疾、种族、性别特征、性别认同和表达、经验水平、教育程度、社会经济地位、国籍、个人外貌、种族、宗教或性取向。
|
||||
|
||||
## 我们的标准
|
||||
|
||||
有助于创造积极环境的行为示例包括:
|
||||
|
||||
- 使用欢迎和包容的语言
|
||||
- 尊重不同的观点和经验
|
||||
- 优雅地接受建设性的批评
|
||||
- 专注于对社区最有利的事情
|
||||
- 对其他社区成员表现出同理心
|
||||
|
||||
参与者不可接受的行为示例包括:
|
||||
|
||||
- 使用性化语言或图像以及不受欢迎的性关注或挑逗
|
||||
- 故意挑衅、侮辱/贬低性评论和个人或政治攻击
|
||||
- 公开或私下骚扰
|
||||
- 未经明确许可发布他人的私人信息,如物理或电子地址
|
||||
- 其他在专业环境中合理认为不适当的行为
|
||||
|
||||
## 我们的责任
|
||||
|
||||
项目维护者有责任澄清可接受行为的标准,并期望对任何不可接受行为采取适当和公平的纠正措施。
|
||||
|
||||
项目维护者有权利和责任删除、编辑或拒绝与本行为准则不一致的评论、提交、代码、维基编辑、问题和其他贡献,或暂时或永久禁止任何贡献者进行他们认为不适当、威胁、冒犯或有害的其他行为。
|
||||
|
||||
## 适用范围
|
||||
|
||||
本行为准则适用于项目空间内和公共空间中代表项目或其社区的个人。代表项目或社区的示例包括使用官方项目电子邮件地址,通过官方社交媒体账户发布,或在在线或离线活动中作为指定代表。项目的代表性可能由项目维护者进一步定义和澄清。
|
||||
|
||||
## 执行
|
||||
|
||||
滥用、骚扰或其他不可接受行为的实例可以通过联系项目团队 hi@cline.bot 报告。所有投诉将被审查和调查,并将导致根据情况认为必要和适当的回应。项目团队有义务对事件报告者保密。具体执行政策的详细信息可能会单独发布。
|
||||
|
||||
未能善意遵守或执行行为准则的项目维护者可能会面临由项目领导的其他成员决定的临时或永久后果。
|
||||
|
||||
## 归属
|
||||
|
||||
本行为准则改编自 [贡献者公约][主页],版本 1.4,可在 https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 获取。
|
||||
|
||||
[主页]: https://www.contributor-covenant.org
|
||||
|
||||
有关此行为准则的常见问题的答案,请参见 https://www.contributor-covenant.org/faq
|
||||
@@ -0,0 +1,82 @@
|
||||
# 贡献到 Cline
|
||||
|
||||
我们很高兴您有兴趣为 Cline 做出贡献。无论您是修复错误、添加功能还是改进我们的文档,每一份贡献都让 Cline 更加智能!为了保持我们的社区充满活力和欢迎,所有成员必须遵守我们的[行为准则](CODE_OF_CONDUCT.md)。
|
||||
|
||||
## 报告错误或问题
|
||||
|
||||
错误报告有助于让 Cline 对每个人都更好!在创建新问题之前,请先[搜索现有问题](https://github.com/cline/cline/issues)以避免重复。当您准备好报告错误时,请前往我们的[问题页面](https://github.com/cline/cline/issues/new/choose),在那里您会找到一个模板来帮助您填写相关信息。
|
||||
|
||||
<blockquote class='warning-note'>
|
||||
🔐 <b>重要:</b>如果您发现安全漏洞,请使用<a href="https://github.com/cline/cline/security/advisories/new">Github 安全工具私下报告</a>。
|
||||
</blockquote>
|
||||
|
||||
## 决定要做什么
|
||||
|
||||
寻找一个好的首次贡献?查看标记为["good first issue"](https://github.com/cline/cline/labels/good%20first%20issue)或["help wanted"](https://github.com/cline/cline/labels/help%20wanted)的问题。这些是专门为新贡献者策划的领域,我们非常欢迎您的帮助!
|
||||
|
||||
我们也欢迎对我们的[文档](https://github.com/cline/cline/tree/main/docs)做出贡献!无论是修正错别字、改进现有指南,还是创建新的教育内容 - 我们希望建立一个社区驱动的资源库,帮助每个人充分利用 Cline。您可以从深入研究 `/docs` 并寻找需要改进的地方开始。
|
||||
|
||||
如果您计划开发一个更大的功能,请先创建一个[功能请求](https://github.com/cline/cline/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop),以便我们讨论它是否符合 Cline 的愿景。
|
||||
|
||||
## 开发设置
|
||||
|
||||
1. **VS Code 扩展**
|
||||
|
||||
- 打开项目时,VS Code 会提示您安装推荐的扩展
|
||||
- 这些扩展是开发所必需的 - 请接受所有安装提示
|
||||
- 如果您忽略了提示,可以从扩展面板手动安装它们
|
||||
|
||||
2. **本地开发**
|
||||
- 运行 `npm run install:all` 安装依赖项
|
||||
- 运行 `npm run test` 本地运行测试
|
||||
- 提交 PR 之前,运行 `npm run format:fix` 格式化您的代码
|
||||
|
||||
## 编写和提交代码
|
||||
|
||||
任何人都可以为 Cline 贡献代码,但我们要求您遵循以下指南,以确保您的贡献能够顺利集成:
|
||||
|
||||
1. **保持 Pull Request 集中**
|
||||
|
||||
- 将 PR 限制为单个功能或错误修复
|
||||
- 将较大的更改拆分为较小的相关 PR
|
||||
- 将更改分为逻辑提交,以便独立审查
|
||||
|
||||
2. **代码质量**
|
||||
|
||||
- 运行 `npm run lint` 检查代码风格
|
||||
- 运行 `npm run format` 自动格式化代码
|
||||
- 所有 PR 必须通过 CI 检查,包括 lint 和格式化
|
||||
- 提交前解决所有 ESLint 警告或错误
|
||||
- 遵循 TypeScript 最佳实践并保持类型安全
|
||||
|
||||
3. **测试**
|
||||
|
||||
- 为新功能添加测试
|
||||
- 运行 `npm test` 确保所有测试通过
|
||||
- 如果您的更改影响现有测试,请更新它们
|
||||
- 在适当的情况下包括单元测试和集成测试
|
||||
|
||||
4. **提交指南**
|
||||
|
||||
- 编写清晰、描述性的提交消息
|
||||
- 使用常规提交格式(例如,“feat:”,“fix:”,“docs:”)
|
||||
- 在提交中引用相关问题,使用 #issue-number
|
||||
|
||||
5. **提交前**
|
||||
|
||||
- 将您的分支重新基于最新的 main
|
||||
- 确保您的分支成功构建
|
||||
- 仔细检查所有测试是否通过
|
||||
- 检查您的更改是否有任何调试代码或控制台日志
|
||||
|
||||
6. **Pull Request 描述**
|
||||
- 清楚描述您的更改内容
|
||||
- 包括测试更改的步骤
|
||||
- 列出任何重大更改
|
||||
- 对于 UI 更改,添加截图
|
||||
|
||||
## 贡献协议
|
||||
|
||||
通过提交 pull request,您同意您的贡献将根据与项目相同的许可证([Apache 2.0](LICENSE))进行许可。
|
||||
|
||||
记住:为 Cline 做贡献不仅仅是编写代码 - 这是成为一个社区的一部分,共同塑造 AI 辅助开发的未来。让我们一起构建一些令人惊叹的东西!🚀
|
||||
@@ -0,0 +1,162 @@
|
||||
# Cline – OpenRouter 排名第一
|
||||
|
||||
<p align="center">
|
||||
<img src="https://media.githubusercontent.com/media/cline/cline/main/assets/docs/demo.gif" width="100%" />
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
<table>
|
||||
<tbody>
|
||||
<td align="center">
|
||||
<a href="https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev" target="_blank"><strong>在 VS Marketplace 下载</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://discord.gg/cline" target="_blank"><strong>Discord</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://www.reddit.com/r/cline/" target="_blank"><strong>r/cline</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/cline/cline/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop" target="_blank"><strong>功能请求</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://cline.bot/join-us" target="_blank"><strong>我们正在招聘!</strong></a>
|
||||
</td>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
认识 Cline,一个可以使用你的 **CLI** 和 **编辑器** 的 AI 助手。
|
||||
|
||||
感谢 [Claude 3.5 Sonnet 的代理编码能力](https://www-cdn.anthropic.com/fed9cc193a14b84131812372d8d5857f8f304c52/Model_Card_Claude_3_Addendum.pdf),Cline 可以一步步处理复杂的软件开发任务。通过允许他创建和编辑文件、探索大型项目、使用浏览器和执行终端命令(在你授予权限后),他可以提供超越代码完成或技术支持的帮助。Cline 甚至可以使用 Model Context Protocol (MCP) 创建新工具并扩展自己的能力。虽然自主 AI 脚本传统上在沙盒环境中运行,但此扩展提供了一个人机交互的 GUI 来批准每个文件更改和终端命令,提供了一种安全且可访问的方式来探索代理 AI 的潜力。
|
||||
|
||||
1. 输入你的任务并添加图像,将模型转换为功能应用程序或通过截图修复错误。
|
||||
2. Cline 首先分析你的文件结构和源代码 AST,运行正则表达式搜索,并阅读相关文件以了解现有项目。通过仔细管理添加到上下文中的信息,Cline 即使在大型复杂项目中也能提供有价值的帮助,而不会使上下文窗口过载。
|
||||
3. 一旦 Cline 获得所需信息,他可以:
|
||||
- 创建和编辑文件 + 监控 linter/编译器错误,从而主动修复诸如缺少导入和语法错误等问题。
|
||||
- 直接在你的终端中执行命令并监控其输出,从而在编辑文件后对开发服务器问题做出反应。
|
||||
- 对于 Web 开发任务,Cline 可以在无头浏览器中启动网站,点击、输入、滚动并捕获截图和控制台日志,从而修复运行时错误和视觉错误。
|
||||
4. 当任务完成时,Cline 将通过终端命令如 `open -a "Google Chrome" index.html` 向你展示结果,你可以通过点击按钮运行该命令。
|
||||
|
||||
> [!提示]
|
||||
> 使用 `CMD/CTRL + Shift + P` 快捷键打开命令面板并输入 "Cline: Open In New Tab" 将扩展作为标签在编辑器中打开。这让你可以与文件资源管理器并排使用 Cline,更清楚地看到他如何改变你的工作空间。
|
||||
|
||||
---
|
||||
|
||||
<img align="right" width="340" src="https://github.com/user-attachments/assets/3cf21e04-7ce9-4d22-a7b9-ba2c595e88a4">
|
||||
|
||||
### 使用任何 API 和模型
|
||||
|
||||
Cline 支持 OpenRouter、Anthropic、OpenAI、Google Gemini、AWS Bedrock、Azure 和 GCP Vertex 等 API 提供商。你还可以配置任何兼容 OpenAI 的 API,或通过 LM Studio/Ollama 使用本地模型。如果你使用 OpenRouter,扩展会获取他们的最新模型列表,让你在新模型可用时立即使用。
|
||||
|
||||
扩展还会跟踪整个任务循环和单个请求的总令牌和 API 使用成本,让你在每一步都了解支出情况。
|
||||
|
||||
<!-- 透明像素以在浮动图像后创建换行 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="370" src="https://github.com/user-attachments/assets/81be79a8-1fdb-4028-9129-5fe055e01e76">
|
||||
|
||||
### 在终端中运行命令
|
||||
|
||||
感谢 VSCode v1.93 中的新 [终端 shell 集成更新](https://code.visualstudio.com/updates/v1_93#_terminal-shell-integration-api),Cline 可以直接在你的终端中执行命令并接收输出。这使他能够执行广泛的任务,从安装包和运行构建脚本到部署应用程序、管理数据库和执行测试,同时适应你的开发环境和工具链以正确完成工作。
|
||||
|
||||
对于长时间运行的进程如开发服务器,使用“在运行时继续”按钮让 Cline 在命令后台运行时继续任务。当 Cline 工作时,他会在过程中收到任何新的终端输出通知,让他对可能出现的问题做出反应,例如编辑文件时的编译时错误。
|
||||
|
||||
<!-- 透明像素以在浮动图像后创建换行 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="400" src="https://github.com/user-attachments/assets/c5977833-d9b8-491e-90f9-05f9cd38c588">
|
||||
|
||||
### 创建和编辑文件
|
||||
|
||||
Cline 可以直接在你的编辑器中创建和编辑文件,向你展示更改的差异视图。你可以直接在差异视图编辑器中编辑或恢复 Cline 的更改,或在聊天中提供反馈,直到你对结果满意。Cline 还会监控 linter/编译器错误(缺少导入、语法错误等),以便他在过程中自行修复出现的问题。
|
||||
|
||||
Cline 所做的所有更改都会记录在你的文件时间轴中,提供了一种简单的方法来跟踪和恢复修改(如果需要)。
|
||||
|
||||
<!-- 透明像素以在浮动图像后创建换行 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="370" src="https://github.com/user-attachments/assets/bc2e85ba-dfeb-4fe6-9942-7cfc4703cbe5">
|
||||
|
||||
### 使用浏览器
|
||||
|
||||
借助 Claude 3.5 Sonnet 的新 [计算机使用](https://www.anthropic.com/news/3-5-models-and-computer-use) 功能,Cline 可以启动浏览器,点击元素,输入文本和滚动,在每一步捕获截图和控制台日志。这允许进行交互式调试、端到端测试,甚至是一般的网页使用!这使他能够自主修复视觉错误和运行时问题,而无需你亲自操作和复制粘贴错误日志。
|
||||
|
||||
试试让 Cline “测试应用程序”,看看他如何运行 `npm run dev` 命令,在浏览器中启动你本地运行的开发服务器,并执行一系列测试以确认一切正常。[在这里查看演示。](https://x.com/sdrzn/status/1850880547825823989)
|
||||
|
||||
<!-- 透明像素以在浮动图像后创建换行 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="350" src="https://github.com/user-attachments/assets/ac0efa14-5c1f-4c26-a42d-9d7c56f5fadd">
|
||||
|
||||
### “添加一个工具……”
|
||||
|
||||
感谢 [Model Context Protocol](https://github.com/modelcontextprotocol),Cline 可以通过自定义工具扩展他的能力。虽然你可以使用 [社区制作的服务器](https://github.com/modelcontextprotocol/servers),但 Cline 可以创建和安装适合你特定工作流程的工具。只需让 Cline “添加一个工具”,他将处理所有事情,从创建新的 MCP 服务器到将其安装到扩展中。这些自定义工具将成为 Cline 工具包的一部分,准备在未来的任务中使用。
|
||||
|
||||
- “添加一个获取 Jira 工单的工具”:检索工单 AC 并让 Cline 开始工作
|
||||
- “添加一个管理 AWS EC2 的工具”:检查服务器指标并上下扩展实例
|
||||
- “添加一个获取最新 PagerDuty 事件的工具”:获取详细信息并让 Cline 修复错误
|
||||
|
||||
<!-- 透明像素以在浮动图像后创建换行 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="360" src="https://github.com/user-attachments/assets/7fdf41e6-281a-4b4b-ac19-020b838b6970">
|
||||
|
||||
### 添加上下文
|
||||
|
||||
**`@url`:** 粘贴一个 URL 以供扩展获取并转换为 markdown,当你想给 Cline 提供最新文档时非常有用
|
||||
|
||||
**`@problems`:** 添加工作区错误和警告(“问题”面板)以供 Cline 修复
|
||||
|
||||
**`@file`:** 添加文件内容,这样你就不必浪费 API 请求批准读取文件(+ 输入以搜索文件)
|
||||
|
||||
**`@folder`:** 一次添加文件夹的文件,以进一步加快你的工作流程
|
||||
|
||||
<!-- 透明像素以在浮动图像后创建换行 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="350" src="https://github.com/user-attachments/assets/140c8606-d3bf-41b9-9a1f-4dbf0d4c90cb">
|
||||
|
||||
### 检查点:比较和恢复
|
||||
|
||||
当 Cline 完成任务时,扩展会在每一步拍摄你的工作区快照。你可以使用“比较”按钮查看快照和当前工作区之间的差异,并使用“恢复”按钮回滚到该点。
|
||||
|
||||
例如,当使用本地 Web 服务器时,你可以使用“仅恢复工作区”快速测试应用程序的不同版本,然后在找到要继续构建的版本时使用“恢复任务和工作区”。这让你可以安全地探索不同的方法而不会丢失进度。
|
||||
|
||||
<!-- 透明像素以在浮动图像后创建换行 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
## 贡献
|
||||
|
||||
要为项目做出贡献,请从我们的 [贡献指南](CONTRIBUTING.md) 开始,了解基础知识。你还可以加入我们的 [Discord](https://discord.gg/cline) 在 `#contributors` 频道与其他贡献者聊天。如果你正在寻找全职工作,请查看我们在 [招聘页面](https://cline.bot/join-us) 上的开放职位!
|
||||
|
||||
<details>
|
||||
<summary>本地开发说明</summary>
|
||||
|
||||
1. 克隆仓库 _(需要 [git-lfs](https://git-lfs.com/))_:
|
||||
```bash
|
||||
git clone https://github.com/cline/cline.git
|
||||
```
|
||||
2. 在 VSCode 中打开项目:
|
||||
```bash
|
||||
code cline
|
||||
```
|
||||
3. 安装扩展和 webview-gui 的必要依赖:
|
||||
```bash
|
||||
npm run install:all
|
||||
```
|
||||
4. 按 `F5`(或 `运行`->`开始调试`)启动以打开一个加载了扩展的新 VSCode 窗口。(如果你在构建项目时遇到问题,可能需要安装 [esbuild problem matchers 扩展](https://marketplace.visualstudio.com/items?itemName=connor4312.esbuild-problem-matchers))
|
||||
|
||||
</details>
|
||||
|
||||
## 许可证
|
||||
|
||||
[Apache 2.0 © 2024 Cline Bot Inc.](./LICENSE)
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# 貢獻者公約行為準則
|
||||
|
||||
## 我們的承諾
|
||||
|
||||
為了促進一個開放和歡迎的環境,我們作為貢獻者和維護者承諾,使我們的項目和社區的參與對每個人來說都是一個無騷擾的體驗,不論年齡、體型、殘疾、種族、性別特徵、性別認同和表達、經驗水平、教育程度、社會經濟地位、國籍、個人外貌、種族、宗教或性取向。
|
||||
|
||||
## 我們的標準
|
||||
|
||||
有助於創造積極環境的行為示例包括:
|
||||
|
||||
- 使用歡迎和包容的語言
|
||||
- 尊重不同的觀點和經驗
|
||||
- 優雅地接受建設性的批評
|
||||
- 專注於對社區最有利的事情
|
||||
- 對其他社區成員表示同情
|
||||
|
||||
參與者不可接受的行為示例包括:
|
||||
|
||||
- 使用性化語言或圖像以及不受歡迎的性注意或挑逗
|
||||
- 騷擾、侮辱/貶低性評論和個人或政治攻擊
|
||||
- 公開或私下騷擾
|
||||
- 未經明確許可發布他人的私人信息,例如物理或電子地址
|
||||
- 其他在專業環境中合理認為不適當的行為
|
||||
|
||||
## 我們的責任
|
||||
|
||||
項目維護者有責任澄清可接受行為的標準,並預期對任何不可接受行為的實例採取適當和公平的糾正行動。
|
||||
|
||||
項目維護者有權利和責任刪除、編輯或拒絕與本行為準則不符的評論、提交、代碼、維基編輯、問題和其他貢獻,或暫時或永久禁止任何他們認為不適當、威脅、冒犯或有害的貢獻者。
|
||||
|
||||
## 範圍
|
||||
|
||||
此行為準則適用於項目空間內以及當個人代表項目或其社區時的公共空間。代表項目或社區的示例包括使用官方項目電子郵件地址、通過官方社交媒體帳戶發布或作為在線或離線活動的指定代表。項目的代表可能由項目維護者進一步定義和澄清。
|
||||
|
||||
## 執行
|
||||
|
||||
濫用、騷擾或其他不可接受行為的實例可以通過聯繫項目團隊 hi@cline.bot 來報告。所有投訴將被審查和調查,並將根據情況作出必要和適當的回應。項目團隊有義務對事件的報告者保密。具體執行政策的詳細信息可能會單獨發布。
|
||||
|
||||
未能善意遵循或執行行為準則的項目維護者可能會面臨由項目領導層其他成員決定的暫時或永久後果。
|
||||
|
||||
## 歸屬
|
||||
|
||||
此行為準則改編自 [Contributor Covenant][homepage],版本 1.4,可在 https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 獲得。
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
有關此行為準則的常見問題的答案,請參見 https://www.contributor-covenant.org/faq
|
||||
@@ -0,0 +1,82 @@
|
||||
# 貢獻於 Cline
|
||||
|
||||
我們很高興您有興趣為 Cline 做出貢獻。無論您是修復錯誤、添加功能還是改進我們的文檔,每一個貢獻都讓 Cline 更加智能!為了保持我們的社區充滿活力和歡迎,所有成員必須遵守我們的[行為準則](CODE_OF_CONDUCT.md)。
|
||||
|
||||
## 報告錯誤或問題
|
||||
|
||||
錯誤報告有助於讓 Cline 對每個人都更好!在創建新問題之前,請[搜索現有問題](https://github.com/cline/cline/issues)以避免重複。當您準備報告錯誤時,請前往我們的[問題頁面](https://github.com/cline/cline/issues/new/choose),您會找到一個模板來幫助您填寫相關信息。
|
||||
|
||||
<blockquote class='warning-note'>
|
||||
🔐 <b>重要:</b> 如果您發現安全漏洞,請使用<a href="https://github.com/cline/cline/security/advisories/new">Github 安全工具私下報告</a>。
|
||||
</blockquote>
|
||||
|
||||
## 決定要做什麼
|
||||
|
||||
尋找一個好的首次貢獻?查看標有["good first issue"](https://github.com/cline/cline/labels/good%20first%20issue)或["help wanted"](https://github.com/cline/cline/labels/help%20wanted)的問題。這些是專門為新貢獻者和我們希望得到幫助的領域策劃的!
|
||||
|
||||
我們也歡迎對我們[文檔](https://github.com/cline/cline/tree/main/docs)的貢獻!無論是修正錯別字、改進現有指南還是創建新的教育內容 - 我們希望建立一個由社區驅動的資源庫,幫助每個人充分利用 Cline。您可以從深入研究 `/docs` 並尋找需要改進的領域開始。
|
||||
|
||||
如果您計劃開發一個更大的功能,請先創建一個[功能請求](https://github.com/cline/cline/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop),以便我們討論它是否符合 Cline 的願景。
|
||||
|
||||
## 開發設置
|
||||
|
||||
1. **VS Code 擴展**
|
||||
|
||||
- 打開項目時,VS Code 會提示您安裝推薦的擴展
|
||||
- 這些擴展是開發所需的 - 請接受所有安裝提示
|
||||
- 如果您忽略了提示,可以從擴展面板手動安裝它們
|
||||
|
||||
2. **本地開發**
|
||||
- 運行 `npm run install:all` 安裝依賴項
|
||||
- 運行 `npm run test` 本地運行測試
|
||||
- 提交 PR 之前,運行 `npm run format:fix` 格式化您的代碼
|
||||
|
||||
## 編寫和提交代碼
|
||||
|
||||
任何人都可以為 Cline 貢獻代碼,但我們要求您遵循以下指南,以確保您的貢獻能夠順利集成:
|
||||
|
||||
1. **保持 Pull Requests 集中**
|
||||
|
||||
- 將 PR 限制在單個功能或錯誤修復
|
||||
- 將較大的更改拆分為較小的相關 PR
|
||||
- 將更改分為邏輯提交,可以獨立審查
|
||||
|
||||
2. **代碼質量**
|
||||
|
||||
- 運行 `npm run lint` 檢查代碼風格
|
||||
- 運行 `npm run format` 自動格式化代碼
|
||||
- 所有 PR 必須通過包括 lint 和格式化在內的 CI 檢查
|
||||
- 提交前解決所有 ESLint 警告或錯誤
|
||||
- 遵循 TypeScript 最佳實踐並保持類型安全
|
||||
|
||||
3. **測試**
|
||||
|
||||
- 為新功能添加測試
|
||||
- 運行 `npm test` 確保所有測試通過
|
||||
- 如果您的更改影響現有測試,請更新它們
|
||||
- 在適當的地方包括單元測試和集成測試
|
||||
|
||||
4. **提交指南**
|
||||
|
||||
- 撰寫清晰、描述性的提交消息
|
||||
- 使用常規提交格式(例如 "feat:"、"fix:"、"docs:")
|
||||
- 在提交中引用相關問題,使用 #issue-number
|
||||
|
||||
5. **提交前**
|
||||
|
||||
- 將您的分支重新基於最新的 main
|
||||
- 確保您的分支成功構建
|
||||
- 仔細檢查所有測試是否通過
|
||||
- 檢查您的更改是否有任何調試代碼或控制台日誌
|
||||
|
||||
6. **Pull Request 描述**
|
||||
- 清楚地描述您的更改內容
|
||||
- 包括測試更改的步驟
|
||||
- 列出任何重大更改
|
||||
- 為 UI 更改添加截圖
|
||||
|
||||
## 貢獻協議
|
||||
|
||||
通過提交 pull request,您同意您的貢獻將根據與項目相同的許可證([Apache 2.0](LICENSE))進行許可。
|
||||
|
||||
記住:貢獻於 Cline 不僅僅是編寫代碼 - 這是關於成為一個塑造 AI 輔助開發未來的社區的一部分。讓我們一起創造一些驚人的東西!🚀
|
||||
@@ -0,0 +1,161 @@
|
||||
# Cline – OpenRouter 上的 \#1
|
||||
|
||||
<p align="center">
|
||||
<img src="https://media.githubusercontent.com/media/cline/cline/main/assets/docs/demo.gif" width="100%" />
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
<table>
|
||||
<tbody>
|
||||
<td align="center">
|
||||
<a href="https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev" target="_blank"><strong>在 VS Marketplace 下載</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://discord.gg/cline" target="_blank"><strong>Discord</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://www.reddit.com/r/cline/" target="_blank"><strong>r/cline</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/cline/cline/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop" target="_blank"><strong>功能請求</strong></a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://cline.bot/join-us" target="_blank"><strong>我們正在招聘!</strong></a>
|
||||
</td>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
認識 Cline,一個可以使用你的 **CLI** 和 **編輯器** 的 AI 助手。
|
||||
|
||||
感謝 [Claude 3.5 Sonnet 的代理編碼能力](https://www-cdn.anthropic.com/fed9cc193a14b84131812372d8d5857f8f304c52/Model_Card_Claude_3_Addendum.pdf),Cline 可以一步步處理複雜的軟件開發任務。通過允許他創建和編輯文件、探索大型項目、使用瀏覽器和執行終端命令(在你授予權限後),他可以提供超越代碼完成或技術支持的幫助。Cline 甚至可以使用 Model Context Protocol (MCP) 創建新工具並擴展自己的能力。雖然自主 AI 腳本傳統上在沙盒環境中運行,但此擴展提供了一個人機交互的 GUI 來批准每個文件更改和終端命令,提供了一種安全且可訪問的方式來探索代理 AI 的潛力。
|
||||
|
||||
1. 輸入你的任務並添加圖像,將模型轉換為功能應用程序或通過截圖修復錯誤。
|
||||
2. Cline 首先分析你的文件結構和源代碼 AST,運行正則表達式搜索,並閱讀相關文件以了解現有項目。通過仔細管理添加到上下文中的信息,Cline 即使在大型複雜項目中也能提供有價值的幫助,而不會使上下文窗口過載。
|
||||
3. 一旦 Cline 獲得所需信息,他可以:
|
||||
- 創建和編輯文件 + 監控 linter/編譯器錯誤,從而主動修復諸如缺少導入和語法錯誤等問題。
|
||||
- 直接在你的終端中執行命令並監控其輸出,從而在編輯文件後對開發服務器問題做出反應。
|
||||
- 對於 Web 開發任務,Cline 可以在無頭瀏覽器中啟動網站,點擊、輸入、滾動並捕獲截圖和控制台日誌,從而修復運行時錯誤和視覺錯誤。
|
||||
4. 當任務完成時,Cline 將通過終端命令如 `open -a "Google Chrome" index.html` 向你展示結果,你可以通過點擊按鈕運行該命令。
|
||||
|
||||
> [!提示]
|
||||
> 使用 `CMD/CTRL + Shift + P` 快捷鍵打開命令面板並輸入 "Cline: Open In New Tab" 將擴展作為標籤在編輯器中打開。這讓你可以與文件資源管理器並排使用 Cline,更清楚地看到他如何改變你的工作空間。
|
||||
|
||||
---
|
||||
|
||||
<img align="right" width="340" src="https://github.com/user-attachments/assets/3cf21e04-7ce9-4d22-a7b9-ba2c595e88a4">
|
||||
|
||||
### 使用任何 API 和模型
|
||||
|
||||
Cline 支持 OpenRouter、Anthropic、OpenAI、Google Gemini、AWS Bedrock、Azure 和 GCP Vertex 等 API 提供商。你還可以配置任何兼容 OpenAI 的 API,或通過 LM Studio/Ollama 使用本地模型。如果你使用 OpenRouter,擴展會獲取他們的最新模型列表,讓你在新模型可用時立即使用。
|
||||
|
||||
擴展還會跟蹤整個任務循環和單個請求的總令牌和 API 使用成本,讓你在每一步都了解支出情況。
|
||||
|
||||
<!-- 透明像素以在浮動圖像後創建換行 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="370" src="https://github.com/user-attachments/assets/81be79a8-1fdb-4028-9129-5fe055e01e76">
|
||||
|
||||
### 在終端中運行命令
|
||||
|
||||
感謝 VSCode v1.93 中的新 [終端 shell 集成更新](https://code.visualstudio.com/updates/v1_93#_terminal-shell-integration-api),Cline 可以直接在你的終端中執行命令並接收輸出。這使他能夠執行廣泛的任務,從安裝包和運行構建腳本到部署應用程序、管理數據庫和執行測試,同時適應你的開發環境和工具鏈以正確完成工作。
|
||||
|
||||
對於長時間運行的進程如開發服務器,使用“在運行時繼續”按鈕讓 Cline 在命令後台運行時繼續任務。當 Cline 工作時,他會在過程中收到任何新的終端輸出通知,讓他對可能出現的問題做出反應,例如編輯文件時的編譯時錯誤。
|
||||
|
||||
<!-- 透明像素以在浮動圖像後創建換行 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="400" src="https://github.com/user-attachments/assets/c5977833-d9b8-491e-90f9-05f9cd38c588">
|
||||
|
||||
### 創建和編輯文件
|
||||
|
||||
Cline 可以直接在你的編輯器中創建和編輯文件,向你展示更改的差異視圖。你可以直接在差異視圖編輯器中編輯或恢復 Cline 的更改,或在聊天中提供反饋,直到你對結果滿意。Cline 還會監控 linter/編譯器錯誤(缺少導入、語法錯誤等),以便他在過程中自行修復出現的問題。
|
||||
|
||||
Cline 所做的所有更改都會記錄在你的文件時間軸中,提供了一種簡單的方法來跟蹤和恢復修改(如果需要)。
|
||||
|
||||
<!-- 透明像素以在浮動圖像後創建換行 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="370" src="https://github.com/user-attachments/assets/bc2e85ba-dfeb-4fe6-9942-7cfc4703cbe5">
|
||||
|
||||
### 使用瀏覽器
|
||||
|
||||
借助 Claude 3.5 Sonnet 的新 [計算機使用](https://www.anthropic.com/news/3-5-models-and-computer-use) 功能,Cline 可以啟動瀏覽器,點擊元素,輸入文本和滾動,在每一步捕獲截圖和控制台日誌。這允許進行交互式調試、端到端測試,甚至是一般的網頁使用!這使他能夠自主修復視覺錯誤和運行時問題,而無需你親自操作和複製粘貼錯誤日誌。
|
||||
|
||||
試試讓 Cline “測試應用程序”,看看他如何運行 `npm run dev` 命令,在瀏覽器中啟動你本地運行的開發服務器,並執行一系列測試以確認一切正常。[在這裡查看演示。](https://x.com/sdrzn/status/1850880547825823989)
|
||||
|
||||
<!-- 透明像素以在浮動圖像後創建換行 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="350" src="https://github.com/user-attachments/assets/ac0efa14-5c1f-4c26-a42d-9d7c56f5fadd">
|
||||
|
||||
### “添加一個工具……”
|
||||
|
||||
感謝 [Model Context Protocol](https://github.com/modelcontextprotocol),Cline 可以通過自定義工具擴展他的能力。雖然你可以使用 [社區製作的服務器](https://github.com/modelcontextprotocol/servers),但 Cline 可以創建和安裝適合你特定工作流程的工具。只需讓 Cline “添加一個工具”,他將處理所有事情,從創建新的 MCP 服務器到將其安裝到擴展中。這些自定義工具將成為 Cline 工具包的一部分,準備在未來的任務中使用。
|
||||
|
||||
- “添加一個獲取 Jira 工單的工具”:檢索工單 AC 並讓 Cline 開始工作
|
||||
- “添加一個管理 AWS EC2 的工具”:檢查服務器指標並上下擴展實例
|
||||
- “添加一個獲取最新 PagerDuty 事件的工具”:獲取詳細信息並讓 Cline 修復錯誤
|
||||
|
||||
<!-- 透明像素以在浮動圖像後創建換行 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="left" width="360" src="https://github.com/user-attachments/assets/7fdf41e6-281a-4b4b-ac19-020b838b6970">
|
||||
|
||||
### 添加上下文
|
||||
|
||||
**`@url`:** 粘貼一個 URL 以供擴展獲取並轉換為 markdown,當你想給 Cline 提供最新文檔時非常有用
|
||||
|
||||
**`@problems`:** 添加工作區錯誤和警告(“問題”面板)以供 Cline 修復
|
||||
|
||||
**`@file`:** 添加文件內容,這樣你就不必浪費 API 請求批准讀取文件(+ 輸入以搜索文件)
|
||||
|
||||
**`@folder`:** 一次添加文件夾的文件,以進一步加快你的工作流程
|
||||
|
||||
<!-- 透明像素以在浮動圖像後創建換行 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
<img align="right" width="350" src="https://github.com/user-attachments/assets/140c8606-d3bf-41b9-9a1f-4dbf0d4c90cb">
|
||||
|
||||
### 檢查點:比較和恢復
|
||||
|
||||
當 Cline 完成任務時,擴展會在每一步拍攝你的工作區快照。你可以使用“比較”按鈕查看快照和當前工作區之間的差異,並使用“恢復”按鈕回滾到該點。
|
||||
|
||||
例如,當使用本地 Web 服務器時,你可以使用“僅恢復工作區”快速測試應用程序的不同版本,然後在找到要繼續構建的版本時使用“恢復任務和工作區”。這讓你可以安全地探索不同的方法而不會丟失進度。
|
||||
|
||||
<!-- 透明像素以在浮動圖像後創建換行 -->
|
||||
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
## 貢獻
|
||||
|
||||
要為項目做出貢獻,請從我們的 [貢獻指南](CONTRIBUTING.md) 開始,了解基礎知識。你還可以加入我們的 [Discord](https://discord.gg/cline) 在 `#contributors` 頻道與其他貢獻者聊天。如果你正在尋找全職工作,請查看我們在 [招聘頁面](https://cline.bot/join-us) 上的開放職位!
|
||||
|
||||
<details>
|
||||
<summary>本地開發說明</summary>
|
||||
|
||||
1. 克隆倉庫 _(需要 [git-lfs](https://git-lfs.com/))_:
|
||||
```bash
|
||||
git clone https://github.com/cline/cline.git
|
||||
```
|
||||
2. 在 VSCode 中打開項目:
|
||||
```bash
|
||||
code cline
|
||||
```
|
||||
3. 安裝擴展和 webview-gui 的必要依賴:
|
||||
```bash
|
||||
npm run install:all
|
||||
```
|
||||
4. 按 `F5`(或 `運行`->`開始調試`)啟動以打開一個加載了擴展的新 VSCode 窗口。(如果你在構建項目時遇到問題,可能需要安裝 [esbuild problem matchers 擴展](https://marketplace.visualstudio.com/items?itemName=connor4312.esbuild-problem-matchers))
|
||||
|
||||
</details>
|
||||
|
||||
## 許可證
|
||||
|
||||
[Apache 2.0 © 2024 Cline Bot Inc.](./LICENSE)
|
||||
@@ -1,179 +1,254 @@
|
||||
{
|
||||
"name": "claude-dev",
|
||||
"displayName": "Claude Dev",
|
||||
"description": "Autonomous coding agent right in your IDE, capable of creating/editing files, executing commands, and more with your permission every step of the way.",
|
||||
"version": "1.8.0",
|
||||
"icon": "icons/icon.png",
|
||||
"galleryBanner": {
|
||||
"color": "#1E1E1E",
|
||||
"theme": "dark"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.84.0"
|
||||
},
|
||||
"author": {
|
||||
"name": "Saoud Rizwan"
|
||||
},
|
||||
"license": "MIT",
|
||||
"publisher": "saoudrizwan",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/saoudrizwan/claude-dev"
|
||||
},
|
||||
"categories": [
|
||||
"AI",
|
||||
"Chat",
|
||||
"Programming Languages",
|
||||
"Education",
|
||||
"Snippets",
|
||||
"Testing"
|
||||
],
|
||||
"keywords": [
|
||||
"claude",
|
||||
"coding",
|
||||
"agent",
|
||||
"autonomous",
|
||||
"chatgpt",
|
||||
"sonnet",
|
||||
"ai",
|
||||
"llama"
|
||||
],
|
||||
"activationEvents": [],
|
||||
"main": "./dist/extension.js",
|
||||
"contributes": {
|
||||
"viewsContainers": {
|
||||
"activitybar": [
|
||||
{
|
||||
"id": "claude-dev-ActivityBar",
|
||||
"title": "Claude Dev",
|
||||
"icon": "$(robot)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"views": {
|
||||
"claude-dev-ActivityBar": [
|
||||
{
|
||||
"type": "webview",
|
||||
"id": "claude-dev.SidebarProvider",
|
||||
"name": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"commands": [
|
||||
{
|
||||
"command": "claude-dev.plusButtonTapped",
|
||||
"title": "New Task",
|
||||
"icon": "$(add)"
|
||||
},
|
||||
{
|
||||
"command": "claude-dev.historyButtonTapped",
|
||||
"title": "History",
|
||||
"icon": "$(history)"
|
||||
},
|
||||
{
|
||||
"command": "claude-dev.popoutButtonTapped",
|
||||
"title": "Open in Editor",
|
||||
"icon": "$(link-external)"
|
||||
},
|
||||
{
|
||||
"command": "claude-dev.settingsButtonTapped",
|
||||
"title": "Settings",
|
||||
"icon": "$(settings-gear)"
|
||||
},
|
||||
{
|
||||
"command": "claude-dev.openInNewTab",
|
||||
"title": "Open In New Tab",
|
||||
"category": "Claude Dev"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"view/title": [
|
||||
{
|
||||
"command": "claude-dev.plusButtonTapped",
|
||||
"group": "navigation@1",
|
||||
"when": "view == claude-dev.SidebarProvider"
|
||||
},
|
||||
{
|
||||
"command": "claude-dev.historyButtonTapped",
|
||||
"group": "navigation@2",
|
||||
"when": "view == claude-dev.SidebarProvider"
|
||||
},
|
||||
{
|
||||
"command": "claude-dev.popoutButtonTapped",
|
||||
"group": "navigation@3",
|
||||
"when": "view == claude-dev.SidebarProvider"
|
||||
},
|
||||
{
|
||||
"command": "claude-dev.settingsButtonTapped",
|
||||
"group": "navigation@4",
|
||||
"when": "view == claude-dev.SidebarProvider"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run package",
|
||||
"compile": "npm run check-types && npm run lint && node esbuild.js",
|
||||
"watch": "npm-run-all -p watch:*",
|
||||
"watch:esbuild": "node esbuild.js --watch",
|
||||
"watch:tsc": "tsc --noEmit --watch --project tsconfig.json",
|
||||
"package": "npm run build:webview && npm run check-types && npm run lint && node esbuild.js --production",
|
||||
"compile-tests": "tsc -p . --outDir out",
|
||||
"watch-tests": "tsc -p . -w --outDir out",
|
||||
"pretest": "npm run compile-tests && npm run compile && npm run lint",
|
||||
"check-types": "tsc --noEmit",
|
||||
"lint": "eslint src --ext ts",
|
||||
"test": "vscode-test",
|
||||
"install:all": "npm install && cd webview-ui && npm install",
|
||||
"start:webview": "cd webview-ui && npm run start",
|
||||
"build:webview": "cd webview-ui && npm run build",
|
||||
"test:webview": "cd webview-ui && npm run test",
|
||||
"publish:marketplace": "vsce publish && ovsx publish"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/diff": "^5.2.1",
|
||||
"@types/mocha": "^10.0.7",
|
||||
"@types/node": "20.x",
|
||||
"@types/vscode": "^1.84.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.14.1",
|
||||
"@typescript-eslint/parser": "^7.11.0",
|
||||
"@vscode/test-cli": "^0.0.9",
|
||||
"@vscode/test-electron": "^2.4.0",
|
||||
"esbuild": "^0.21.5",
|
||||
"eslint": "^8.57.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/bedrock-sdk": "^0.10.2",
|
||||
"@anthropic-ai/sdk": "^0.26.0",
|
||||
"@anthropic-ai/vertex-sdk": "^0.4.1",
|
||||
"@google/generative-ai": "^0.18.0",
|
||||
"@types/clone-deep": "^4.0.4",
|
||||
"@types/pdf-parse": "^1.1.4",
|
||||
"@types/turndown": "^5.0.5",
|
||||
"@vscode/codicons": "^0.0.36",
|
||||
"axios": "^1.7.4",
|
||||
"cheerio": "^1.0.0",
|
||||
"clone-deep": "^4.0.1",
|
||||
"default-shell": "^2.2.0",
|
||||
"delay": "^6.0.0",
|
||||
"diff": "^5.2.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"globby": "^14.0.2",
|
||||
"isbinaryfile": "^5.0.2",
|
||||
"mammoth": "^1.8.0",
|
||||
"monaco-vscode-textmate-theme-converter": "^0.1.7",
|
||||
"openai": "^4.61.0",
|
||||
"os-name": "^6.0.0",
|
||||
"p-wait-for": "^5.0.2",
|
||||
"pdf-parse": "^1.1.1",
|
||||
"puppeteer-chromium-resolver": "^23.0.0",
|
||||
"puppeteer-core": "^23.4.0",
|
||||
"serialize-error": "^11.0.3",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"tree-sitter-wasms": "^0.1.11",
|
||||
"turndown": "^7.2.0",
|
||||
"web-tree-sitter": "^0.22.6"
|
||||
}
|
||||
"name": "claude-dev",
|
||||
"displayName": "Cline",
|
||||
"description": "Autonomous coding agent right in your IDE, capable of creating/editing files, running commands, using the browser, and more with your permission every step of the way.",
|
||||
"version": "3.2.6",
|
||||
"icon": "assets/icons/icon.png",
|
||||
"galleryBanner": {
|
||||
"color": "#617A91",
|
||||
"theme": "dark"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.84.0"
|
||||
},
|
||||
"author": {
|
||||
"name": "Cline Bot Inc."
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"publisher": "saoudrizwan",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cline/cline"
|
||||
},
|
||||
"homepage": "https://cline.bot",
|
||||
"categories": [
|
||||
"AI",
|
||||
"Chat",
|
||||
"Programming Languages",
|
||||
"Education",
|
||||
"Snippets",
|
||||
"Testing"
|
||||
],
|
||||
"keywords": [
|
||||
"cline",
|
||||
"claude",
|
||||
"dev",
|
||||
"mcp",
|
||||
"openrouter",
|
||||
"coding",
|
||||
"agent",
|
||||
"autonomous",
|
||||
"chatgpt",
|
||||
"sonnet",
|
||||
"ai",
|
||||
"llama"
|
||||
],
|
||||
"activationEvents": [],
|
||||
"main": "./dist/extension.js",
|
||||
"contributes": {
|
||||
"viewsContainers": {
|
||||
"activitybar": [
|
||||
{
|
||||
"id": "claude-dev-ActivityBar",
|
||||
"title": "Cline",
|
||||
"icon": "assets/icons/icon.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"views": {
|
||||
"claude-dev-ActivityBar": [
|
||||
{
|
||||
"type": "webview",
|
||||
"id": "claude-dev.SidebarProvider",
|
||||
"name": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"commands": [
|
||||
{
|
||||
"command": "cline.plusButtonClicked",
|
||||
"title": "New Task",
|
||||
"icon": "$(add)"
|
||||
},
|
||||
{
|
||||
"command": "cline.mcpButtonClicked",
|
||||
"title": "MCP Servers",
|
||||
"icon": "$(server)"
|
||||
},
|
||||
{
|
||||
"command": "cline.historyButtonClicked",
|
||||
"title": "History",
|
||||
"icon": "$(history)"
|
||||
},
|
||||
{
|
||||
"command": "cline.popoutButtonClicked",
|
||||
"title": "Open in Editor",
|
||||
"icon": "$(link-external)"
|
||||
},
|
||||
{
|
||||
"command": "cline.settingsButtonClicked",
|
||||
"title": "Settings",
|
||||
"icon": "$(settings-gear)"
|
||||
},
|
||||
{
|
||||
"command": "cline.openInNewTab",
|
||||
"title": "Open In New Tab",
|
||||
"category": "Cline"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"view/title": [
|
||||
{
|
||||
"command": "cline.plusButtonClicked",
|
||||
"group": "navigation@1",
|
||||
"when": "view == claude-dev.SidebarProvider"
|
||||
},
|
||||
{
|
||||
"command": "cline.mcpButtonClicked",
|
||||
"group": "navigation@2",
|
||||
"when": "view == claude-dev.SidebarProvider"
|
||||
},
|
||||
{
|
||||
"command": "cline.historyButtonClicked",
|
||||
"group": "navigation@3",
|
||||
"when": "view == claude-dev.SidebarProvider"
|
||||
},
|
||||
{
|
||||
"command": "cline.popoutButtonClicked",
|
||||
"group": "navigation@4",
|
||||
"when": "view == claude-dev.SidebarProvider"
|
||||
},
|
||||
{
|
||||
"command": "cline.settingsButtonClicked",
|
||||
"group": "navigation@5",
|
||||
"when": "view == claude-dev.SidebarProvider"
|
||||
}
|
||||
]
|
||||
},
|
||||
"configuration": {
|
||||
"title": "Cline",
|
||||
"properties": {
|
||||
"cline.vsCodeLmModelSelector": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"vendor": {
|
||||
"type": "string",
|
||||
"description": "The vendor of the language model (e.g. copilot)"
|
||||
},
|
||||
"family": {
|
||||
"type": "string",
|
||||
"description": "The family of the language model (e.g. gpt-4)"
|
||||
}
|
||||
},
|
||||
"description": "Settings for VSCode Language Model API"
|
||||
},
|
||||
"cline.mcp.mode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"full",
|
||||
"server-use-only",
|
||||
"off"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Enable all MCP functionality (server use and build instructions)",
|
||||
"Enable MCP server use only (excludes instructions about building MCP servers)",
|
||||
"Disable all MCP functionality"
|
||||
],
|
||||
"default": "full",
|
||||
"description": "Controls MCP inclusion in prompts, reduces token usage if you only need access to certain functionality."
|
||||
},
|
||||
"cline.enableCheckpoints": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables extension to save checkpoints of workspace throughout the task."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run package",
|
||||
"compile": "npm run check-types && npm run lint && node esbuild.js",
|
||||
"watch": "npm-run-all -p watch:*",
|
||||
"watch:esbuild": "node esbuild.js --watch",
|
||||
"watch:tsc": "tsc --noEmit --watch --project tsconfig.json",
|
||||
"package": "npm run build:webview && npm run check-types && npm run lint && node esbuild.js --production",
|
||||
"compile-tests": "tsc -p ./tsconfig.test.json --outDir out",
|
||||
"watch-tests": "tsc -p . -w --outDir out",
|
||||
"pretest": "npm run compile-tests && npm run compile && npm run lint",
|
||||
"check-types": "tsc --noEmit",
|
||||
"lint": "eslint src --ext ts",
|
||||
"format": "prettier . --check",
|
||||
"format:fix": "prettier . --write",
|
||||
"test": "vscode-test",
|
||||
"install:all": "npm install && cd webview-ui && npm install",
|
||||
"start:webview": "cd webview-ui && npm run start",
|
||||
"build:webview": "cd webview-ui && npm run build",
|
||||
"test:webview": "cd webview-ui && npm run test",
|
||||
"publish:marketplace": "vsce publish && ovsx publish",
|
||||
"publish:marketplace:prerelease": "vsce publish --pre-release && ovsx publish --pre-release",
|
||||
"prepare": "husky",
|
||||
"changie": "changie"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^5.0.1",
|
||||
"@types/diff": "^5.2.1",
|
||||
"@types/mocha": "^10.0.7",
|
||||
"@types/node": "20.x",
|
||||
"@types/should": "^11.2.0",
|
||||
"@types/vscode": "^1.84.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.14.1",
|
||||
"@typescript-eslint/parser": "^7.11.0",
|
||||
"@vscode/test-cli": "^0.0.9",
|
||||
"@vscode/test-electron": "^2.4.0",
|
||||
"chai": "^4.3.10",
|
||||
"changie": "^1.21.0",
|
||||
"esbuild": "^0.21.5",
|
||||
"eslint": "^8.57.0",
|
||||
"husky": "^9.1.7",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^3.3.3",
|
||||
"should": "^13.2.3",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/bedrock-sdk": "^0.10.2",
|
||||
"@anthropic-ai/sdk": "^0.26.0",
|
||||
"@anthropic-ai/vertex-sdk": "^0.4.1",
|
||||
"@google/generative-ai": "^0.18.0",
|
||||
"@mistralai/mistralai": "^1.3.6",
|
||||
"@modelcontextprotocol/sdk": "^1.0.1",
|
||||
"@types/clone-deep": "^4.0.4",
|
||||
"@types/get-folder-size": "^3.0.4",
|
||||
"@types/pdf-parse": "^1.1.4",
|
||||
"@types/turndown": "^5.0.5",
|
||||
"@vscode/codicons": "^0.0.36",
|
||||
"axios": "^1.7.4",
|
||||
"cheerio": "^1.0.0",
|
||||
"chokidar": "^4.0.1",
|
||||
"clone-deep": "^4.0.1",
|
||||
"default-shell": "^2.2.0",
|
||||
"delay": "^6.0.0",
|
||||
"diff": "^5.2.0",
|
||||
"execa": "^9.5.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"firebase": "^11.2.0",
|
||||
"get-folder-size": "^5.0.0",
|
||||
"globby": "^14.0.2",
|
||||
"isbinaryfile": "^5.0.2",
|
||||
"mammoth": "^1.8.0",
|
||||
"monaco-vscode-textmate-theme-converter": "^0.1.7",
|
||||
"openai": "^4.61.0",
|
||||
"os-name": "^6.0.0",
|
||||
"p-wait-for": "^5.0.2",
|
||||
"pdf-parse": "^1.1.1",
|
||||
"puppeteer-chromium-resolver": "^23.0.0",
|
||||
"puppeteer-core": "^23.4.0",
|
||||
"serialize-error": "^11.0.3",
|
||||
"simple-git": "^3.27.0",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"tree-sitter-wasms": "^0.1.11",
|
||||
"turndown": "^7.2.0",
|
||||
"web-tree-sitter": "^0.22.6",
|
||||
"zod": "^3.23.8"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { ApiHandler, ApiHandlerMessageResponse } from "."
|
||||
import { anthropicDefaultModelId, AnthropicModelId, anthropicModels, ApiHandlerOptions, ModelInfo } from "../shared/api"
|
||||
|
||||
export class AnthropicHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: Anthropic
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new Anthropic({
|
||||
apiKey: this.options.apiKey,
|
||||
baseURL: this.options.anthropicBaseUrl || undefined,
|
||||
})
|
||||
}
|
||||
|
||||
async createMessage(
|
||||
systemPrompt: string,
|
||||
messages: Anthropic.Messages.MessageParam[],
|
||||
tools: Anthropic.Messages.Tool[]
|
||||
): Promise<ApiHandlerMessageResponse> {
|
||||
const modelId = this.getModel().id
|
||||
switch (modelId) {
|
||||
case "claude-3-5-sonnet-20240620":
|
||||
case "claude-3-opus-20240229":
|
||||
case "claude-3-haiku-20240307": {
|
||||
/*
|
||||
The latest message will be the new user message, one before will be the assistant message from a previous request, and the user message before that will be a previously cached user message. So we need to mark the latest user message as ephemeral to cache it for the next request, and mark the second to last user message as ephemeral to let the server know the last message to retrieve from the cache for the current request..
|
||||
*/
|
||||
const userMsgIndices = messages.reduce(
|
||||
(acc, msg, index) => (msg.role === "user" ? [...acc, index] : acc),
|
||||
[] as number[]
|
||||
)
|
||||
const lastUserMsgIndex = userMsgIndices[userMsgIndices.length - 1] ?? -1
|
||||
const secondLastMsgUserIndex = userMsgIndices[userMsgIndices.length - 2] ?? -1
|
||||
const message = await this.client.beta.promptCaching.messages.create(
|
||||
{
|
||||
model: modelId,
|
||||
max_tokens: this.getModel().info.maxTokens,
|
||||
system: [{ text: systemPrompt, type: "text", cache_control: { type: "ephemeral" } }], // setting cache breakpoint for system prompt so new tasks can reuse it
|
||||
messages: messages.map((message, index) => {
|
||||
if (index === lastUserMsgIndex || index === secondLastMsgUserIndex) {
|
||||
return {
|
||||
...message,
|
||||
content:
|
||||
typeof message.content === "string"
|
||||
? [
|
||||
{
|
||||
type: "text",
|
||||
text: message.content,
|
||||
cache_control: { type: "ephemeral" },
|
||||
},
|
||||
]
|
||||
: message.content.map((content, contentIndex) =>
|
||||
contentIndex === message.content.length - 1
|
||||
? { ...content, cache_control: { type: "ephemeral" } }
|
||||
: content
|
||||
),
|
||||
}
|
||||
}
|
||||
return message
|
||||
}),
|
||||
tools, // cache breakpoints go from tools > system > messages, and since tools dont change, we can just set the breakpoint at the end of system (this avoids having to set a breakpoint at the end of tools which by itself does not meet min requirements for haiku caching)
|
||||
tool_choice: { type: "auto" },
|
||||
},
|
||||
(() => {
|
||||
// prompt caching: https://x.com/alexalbert__/status/1823751995901272068
|
||||
// https://github.com/anthropics/anthropic-sdk-typescript?tab=readme-ov-file#default-headers
|
||||
// https://github.com/anthropics/anthropic-sdk-typescript/commit/c920b77fc67bd839bfeb6716ceab9d7c9bbe7393
|
||||
switch (modelId) {
|
||||
case "claude-3-5-sonnet-20240620":
|
||||
return {
|
||||
headers: {
|
||||
"anthropic-beta": "prompt-caching-2024-07-31",
|
||||
},
|
||||
}
|
||||
case "claude-3-haiku-20240307":
|
||||
return {
|
||||
headers: { "anthropic-beta": "prompt-caching-2024-07-31" },
|
||||
}
|
||||
default:
|
||||
return undefined
|
||||
}
|
||||
})()
|
||||
)
|
||||
return { message }
|
||||
}
|
||||
default: {
|
||||
const message = await this.client.messages.create({
|
||||
model: modelId,
|
||||
max_tokens: this.getModel().info.maxTokens,
|
||||
system: [{ text: systemPrompt, type: "text" }],
|
||||
messages,
|
||||
tools,
|
||||
tool_choice: { type: "auto" },
|
||||
})
|
||||
return { message }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): { id: AnthropicModelId; info: ModelInfo } {
|
||||
const modelId = this.options.apiModelId
|
||||
if (modelId && modelId in anthropicModels) {
|
||||
const id = modelId as AnthropicModelId
|
||||
return { id, info: anthropicModels[id] }
|
||||
}
|
||||
return { id: anthropicDefaultModelId, info: anthropicModels[anthropicDefaultModelId] }
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import AnthropicBedrock from "@anthropic-ai/bedrock-sdk"
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { ApiHandler, ApiHandlerMessageResponse } from "."
|
||||
import { ApiHandlerOptions, bedrockDefaultModelId, BedrockModelId, bedrockModels, ModelInfo } from "../shared/api"
|
||||
|
||||
// https://docs.anthropic.com/en/api/claude-on-amazon-bedrock
|
||||
export class AwsBedrockHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: AnthropicBedrock
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new AnthropicBedrock({
|
||||
// Authenticate by either providing the keys below or use the default AWS credential providers, such as
|
||||
// using ~/.aws/credentials or the "AWS_SECRET_ACCESS_KEY" and "AWS_ACCESS_KEY_ID" environment variables.
|
||||
...(this.options.awsAccessKey ? { awsAccessKey: this.options.awsAccessKey } : {}),
|
||||
...(this.options.awsSecretKey ? { awsSecretKey: this.options.awsSecretKey } : {}),
|
||||
...(this.options.awsSessionToken ? { awsSessionToken: this.options.awsSessionToken } : {}),
|
||||
|
||||
// awsRegion changes the aws region to which the request is made. By default, we read AWS_REGION,
|
||||
// and if that's not present, we default to us-east-1. Note that we do not read ~/.aws/config for the region.
|
||||
awsRegion: this.options.awsRegion,
|
||||
})
|
||||
}
|
||||
|
||||
async createMessage(
|
||||
systemPrompt: string,
|
||||
messages: Anthropic.Messages.MessageParam[],
|
||||
tools: Anthropic.Messages.Tool[]
|
||||
): Promise<ApiHandlerMessageResponse> {
|
||||
const message = await this.client.messages.create({
|
||||
model: this.getModel().id,
|
||||
max_tokens: this.getModel().info.maxTokens,
|
||||
system: systemPrompt,
|
||||
messages,
|
||||
tools,
|
||||
tool_choice: { type: "auto" },
|
||||
})
|
||||
return { message }
|
||||
}
|
||||
|
||||
getModel(): { id: BedrockModelId; info: ModelInfo } {
|
||||
const modelId = this.options.apiModelId
|
||||
if (modelId && modelId in bedrockModels) {
|
||||
const id = modelId as BedrockModelId
|
||||
return { id, info: bedrockModels[id] }
|
||||
}
|
||||
return { id: bedrockDefaultModelId, info: bedrockModels[bedrockDefaultModelId] }
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { FunctionCallingMode, GoogleGenerativeAI } from "@google/generative-ai"
|
||||
import { ApiHandler, ApiHandlerMessageResponse } from "."
|
||||
import { ApiHandlerOptions, geminiDefaultModelId, GeminiModelId, geminiModels, ModelInfo } from "../shared/api"
|
||||
import {
|
||||
convertAnthropicMessageToGemini,
|
||||
convertAnthropicToolToGemini,
|
||||
convertGeminiResponseToAnthropic,
|
||||
} from "../utils/gemini-format"
|
||||
|
||||
export class GeminiHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: GoogleGenerativeAI
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
if (!options.geminiApiKey) {
|
||||
throw new Error("API key is required for Google Gemini")
|
||||
}
|
||||
this.options = options
|
||||
this.client = new GoogleGenerativeAI(options.geminiApiKey)
|
||||
}
|
||||
|
||||
async createMessage(
|
||||
systemPrompt: string,
|
||||
messages: Anthropic.Messages.MessageParam[],
|
||||
tools: Anthropic.Messages.Tool[]
|
||||
): Promise<ApiHandlerMessageResponse> {
|
||||
const model = this.client.getGenerativeModel({
|
||||
model: this.getModel().id,
|
||||
systemInstruction: systemPrompt,
|
||||
tools: [{ functionDeclarations: tools.map(convertAnthropicToolToGemini) }],
|
||||
toolConfig: {
|
||||
functionCallingConfig: {
|
||||
mode: FunctionCallingMode.AUTO,
|
||||
},
|
||||
},
|
||||
})
|
||||
const result = await model.generateContent({
|
||||
contents: messages.map(convertAnthropicMessageToGemini),
|
||||
generationConfig: {
|
||||
maxOutputTokens: this.getModel().info.maxTokens,
|
||||
},
|
||||
})
|
||||
const message = convertGeminiResponseToAnthropic(result.response)
|
||||
|
||||
return { message }
|
||||
}
|
||||
|
||||
getModel(): { id: GeminiModelId; info: ModelInfo } {
|
||||
const modelId = this.options.apiModelId
|
||||
if (modelId && modelId in geminiModels) {
|
||||
const id = modelId as GeminiModelId
|
||||
return { id, info: geminiModels[id] }
|
||||
}
|
||||
return { id: geminiDefaultModelId, info: geminiModels[geminiDefaultModelId] }
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,28 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { ApiConfiguration, ModelInfo } from "../shared/api"
|
||||
import { AnthropicHandler } from "./anthropic"
|
||||
import { AwsBedrockHandler } from "./bedrock"
|
||||
import { OpenRouterHandler } from "./openrouter"
|
||||
import { VertexHandler } from "./vertex"
|
||||
import { OpenAiHandler } from "./openai"
|
||||
import { OllamaHandler } from "./ollama"
|
||||
import { GeminiHandler } from "./gemini"
|
||||
import { OpenAiNativeHandler } from "./openai-native"
|
||||
|
||||
export interface ApiHandlerMessageResponse {
|
||||
message: Anthropic.Messages.Message
|
||||
userCredits?: number
|
||||
}
|
||||
import { AnthropicHandler } from "./providers/anthropic"
|
||||
import { AwsBedrockHandler } from "./providers/bedrock"
|
||||
import { OpenRouterHandler } from "./providers/openrouter"
|
||||
import { VertexHandler } from "./providers/vertex"
|
||||
import { OpenAiHandler } from "./providers/openai"
|
||||
import { OllamaHandler } from "./providers/ollama"
|
||||
import { LmStudioHandler } from "./providers/lmstudio"
|
||||
import { GeminiHandler } from "./providers/gemini"
|
||||
import { OpenAiNativeHandler } from "./providers/openai-native"
|
||||
import { ApiStream } from "./transform/stream"
|
||||
import { DeepSeekHandler } from "./providers/deepseek"
|
||||
import { MistralHandler } from "./providers/mistral"
|
||||
import { VsCodeLmHandler } from "./providers/vscode-lm"
|
||||
|
||||
export interface ApiHandler {
|
||||
createMessage(
|
||||
systemPrompt: string,
|
||||
messages: Anthropic.Messages.MessageParam[],
|
||||
tools: Anthropic.Messages.Tool[]
|
||||
): Promise<ApiHandlerMessageResponse>
|
||||
|
||||
createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream
|
||||
getModel(): { id: string; info: ModelInfo }
|
||||
}
|
||||
|
||||
export interface SingleCompletionHandler {
|
||||
completePrompt(prompt: string): Promise<string>
|
||||
}
|
||||
|
||||
export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
|
||||
const { apiProvider, ...options } = configuration
|
||||
switch (apiProvider) {
|
||||
@@ -39,10 +38,18 @@ export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
|
||||
return new OpenAiHandler(options)
|
||||
case "ollama":
|
||||
return new OllamaHandler(options)
|
||||
case "lmstudio":
|
||||
return new LmStudioHandler(options)
|
||||
case "gemini":
|
||||
return new GeminiHandler(options)
|
||||
case "openai-native":
|
||||
return new OpenAiNativeHandler(options)
|
||||
case "deepseek":
|
||||
return new DeepSeekHandler(options)
|
||||
case "mistral":
|
||||
return new MistralHandler(options)
|
||||
case "vscode-lm":
|
||||
return new VsCodeLmHandler(options)
|
||||
default:
|
||||
return new AnthropicHandler(options)
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import OpenAI from "openai"
|
||||
import { ApiHandler, ApiHandlerMessageResponse } from "."
|
||||
import { ApiHandlerOptions, ModelInfo, openAiModelInfoSaneDefaults } from "../shared/api"
|
||||
import { convertToAnthropicMessage, convertToOpenAiMessages } from "../utils/openai-format"
|
||||
|
||||
export class OllamaHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: OpenAI
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new OpenAI({
|
||||
baseURL: (this.options.ollamaBaseUrl || "http://localhost:11434") + "/v1",
|
||||
apiKey: "ollama",
|
||||
})
|
||||
}
|
||||
|
||||
async createMessage(
|
||||
systemPrompt: string,
|
||||
messages: Anthropic.Messages.MessageParam[],
|
||||
tools: Anthropic.Messages.Tool[]
|
||||
): Promise<ApiHandlerMessageResponse> {
|
||||
const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
|
||||
{ role: "system", content: systemPrompt },
|
||||
...convertToOpenAiMessages(messages),
|
||||
]
|
||||
const openAiTools: OpenAI.Chat.ChatCompletionTool[] = tools.map((tool) => ({
|
||||
type: "function",
|
||||
function: {
|
||||
name: tool.name,
|
||||
description: tool.description,
|
||||
parameters: tool.input_schema,
|
||||
},
|
||||
}))
|
||||
const createParams: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = {
|
||||
model: this.options.ollamaModelId ?? "",
|
||||
messages: openAiMessages,
|
||||
tools: openAiTools,
|
||||
tool_choice: "auto",
|
||||
}
|
||||
const completion = await this.client.chat.completions.create(createParams)
|
||||
const errorMessage = (completion as any).error?.message
|
||||
if (errorMessage) {
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
const anthropicMessage = convertToAnthropicMessage(completion)
|
||||
return { message: anthropicMessage }
|
||||
}
|
||||
|
||||
getModel(): { id: string; info: ModelInfo } {
|
||||
return {
|
||||
id: this.options.ollamaModelId ?? "",
|
||||
info: openAiModelInfoSaneDefaults,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import OpenAI from "openai"
|
||||
import { ApiHandler, ApiHandlerMessageResponse } from "."
|
||||
import {
|
||||
ApiHandlerOptions,
|
||||
ModelInfo,
|
||||
openAiNativeDefaultModelId,
|
||||
OpenAiNativeModelId,
|
||||
openAiNativeModels,
|
||||
} from "../shared/api"
|
||||
import { convertToAnthropicMessage, convertToOpenAiMessages } from "../utils/openai-format"
|
||||
import { convertO1ResponseToAnthropicMessage, convertToO1Messages } from "../utils/o1-format"
|
||||
|
||||
export class OpenAiNativeHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: OpenAI
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new OpenAI({
|
||||
apiKey: this.options.openAiNativeApiKey,
|
||||
})
|
||||
}
|
||||
|
||||
async createMessage(
|
||||
systemPrompt: string,
|
||||
messages: Anthropic.Messages.MessageParam[],
|
||||
tools: Anthropic.Messages.Tool[]
|
||||
): Promise<ApiHandlerMessageResponse> {
|
||||
const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
|
||||
{ role: "system", content: systemPrompt },
|
||||
...convertToOpenAiMessages(messages),
|
||||
]
|
||||
const openAiTools: OpenAI.Chat.ChatCompletionTool[] = tools.map((tool) => ({
|
||||
type: "function",
|
||||
function: {
|
||||
name: tool.name,
|
||||
description: tool.description,
|
||||
parameters: tool.input_schema,
|
||||
},
|
||||
}))
|
||||
|
||||
let createParams: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming
|
||||
|
||||
switch (this.getModel().id) {
|
||||
case "o1-preview":
|
||||
case "o1-mini":
|
||||
createParams = {
|
||||
model: this.getModel().id,
|
||||
max_completion_tokens: this.getModel().info.maxTokens,
|
||||
messages: convertToO1Messages(convertToOpenAiMessages(messages), systemPrompt),
|
||||
}
|
||||
break
|
||||
default:
|
||||
createParams = {
|
||||
model: this.getModel().id,
|
||||
max_completion_tokens: this.getModel().info.maxTokens,
|
||||
messages: openAiMessages,
|
||||
tools: openAiTools,
|
||||
tool_choice: "auto",
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
const completion = await this.client.chat.completions.create(createParams)
|
||||
const errorMessage = (completion as any).error?.message
|
||||
if (errorMessage) {
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
|
||||
let anthropicMessage: Anthropic.Messages.Message
|
||||
switch (this.getModel().id) {
|
||||
case "o1-preview":
|
||||
case "o1-mini":
|
||||
anthropicMessage = convertO1ResponseToAnthropicMessage(completion)
|
||||
break
|
||||
default:
|
||||
anthropicMessage = convertToAnthropicMessage(completion)
|
||||
break
|
||||
}
|
||||
|
||||
return { message: anthropicMessage }
|
||||
}
|
||||
|
||||
getModel(): { id: OpenAiNativeModelId; info: ModelInfo } {
|
||||
const modelId = this.options.apiModelId
|
||||
if (modelId && modelId in openAiNativeModels) {
|
||||
const id = modelId as OpenAiNativeModelId
|
||||
return { id, info: openAiNativeModels[id] }
|
||||
}
|
||||
return { id: openAiNativeDefaultModelId, info: openAiNativeModels[openAiNativeDefaultModelId] }
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import OpenAI, { AzureOpenAI } from "openai"
|
||||
import { ApiHandler, ApiHandlerMessageResponse } from "."
|
||||
import { ApiHandlerOptions, ModelInfo, openAiModelInfoSaneDefaults } from "../shared/api"
|
||||
import { convertToAnthropicMessage, convertToOpenAiMessages } from "../utils/openai-format"
|
||||
|
||||
export class OpenAiHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: OpenAI
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
// Azure API shape slightly differs from the core API shape: https://github.com/openai/openai-node?tab=readme-ov-file#microsoft-azure-openai
|
||||
if (this.options.openAiBaseUrl?.toLowerCase().includes("azure.com")) {
|
||||
this.client = new AzureOpenAI({
|
||||
baseURL: this.options.openAiBaseUrl,
|
||||
apiKey: this.options.openAiApiKey,
|
||||
// https://learn.microsoft.com/en-us/azure/ai-services/openai/api-version-deprecation
|
||||
// https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#api-specs
|
||||
apiVersion: "2024-08-01-preview",
|
||||
})
|
||||
} else {
|
||||
this.client = new OpenAI({
|
||||
baseURL: this.options.openAiBaseUrl,
|
||||
apiKey: this.options.openAiApiKey,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async createMessage(
|
||||
systemPrompt: string,
|
||||
messages: Anthropic.Messages.MessageParam[],
|
||||
tools: Anthropic.Messages.Tool[]
|
||||
): Promise<ApiHandlerMessageResponse> {
|
||||
const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
|
||||
{ role: "system", content: systemPrompt },
|
||||
...convertToOpenAiMessages(messages),
|
||||
]
|
||||
const openAiTools: OpenAI.Chat.ChatCompletionTool[] = tools.map((tool) => ({
|
||||
type: "function",
|
||||
function: {
|
||||
name: tool.name,
|
||||
description: tool.description,
|
||||
parameters: tool.input_schema,
|
||||
},
|
||||
}))
|
||||
const createParams: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = {
|
||||
model: this.options.openAiModelId ?? "",
|
||||
messages: openAiMessages,
|
||||
tools: openAiTools,
|
||||
tool_choice: "auto",
|
||||
}
|
||||
const completion = await this.client.chat.completions.create(createParams)
|
||||
const errorMessage = (completion as any).error?.message
|
||||
if (errorMessage) {
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
const anthropicMessage = convertToAnthropicMessage(completion)
|
||||
return { message: anthropicMessage }
|
||||
}
|
||||
|
||||
getModel(): { id: string; info: ModelInfo } {
|
||||
return {
|
||||
id: this.options.openAiModelId ?? "",
|
||||
info: openAiModelInfoSaneDefaults,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,288 +0,0 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import OpenAI from "openai"
|
||||
import { ApiHandler, ApiHandlerMessageResponse } from "."
|
||||
import {
|
||||
ApiHandlerOptions,
|
||||
ModelInfo,
|
||||
openRouterDefaultModelId,
|
||||
OpenRouterModelId,
|
||||
openRouterModels,
|
||||
} from "../shared/api"
|
||||
import { convertToAnthropicMessage, convertToOpenAiMessages } from "../utils/openai-format"
|
||||
import axios from "axios"
|
||||
import { convertO1ResponseToAnthropicMessage, convertToO1Messages } from "../utils/o1-format"
|
||||
|
||||
export class OpenRouterHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: OpenAI
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new OpenAI({
|
||||
baseURL: "https://openrouter.ai/api/v1",
|
||||
apiKey: this.options.openRouterApiKey,
|
||||
defaultHeaders: {
|
||||
"HTTP-Referer": "https://github.com/saoudrizwan/claude-dev", // Optional, for including your app on openrouter.ai rankings.
|
||||
"X-Title": "claude-dev", // Optional. Shows in rankings on openrouter.ai.
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async createMessage(
|
||||
systemPrompt: string,
|
||||
messages: Anthropic.Messages.MessageParam[],
|
||||
tools: Anthropic.Messages.Tool[]
|
||||
): Promise<ApiHandlerMessageResponse> {
|
||||
// Convert Anthropic messages to OpenAI format
|
||||
const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
|
||||
{ role: "system", content: systemPrompt },
|
||||
...convertToOpenAiMessages(messages),
|
||||
]
|
||||
|
||||
// prompt caching: https://openrouter.ai/docs/prompt-caching
|
||||
switch (this.getModel().id) {
|
||||
case "anthropic/claude-3.5-sonnet:beta":
|
||||
case "anthropic/claude-3-haiku:beta":
|
||||
case "anthropic/claude-3-opus:beta":
|
||||
openAiMessages[0] = {
|
||||
role: "system",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: systemPrompt,
|
||||
// @ts-ignore-next-line
|
||||
cache_control: { type: "ephemeral" },
|
||||
},
|
||||
],
|
||||
}
|
||||
// Add cache_control to the last two user messages
|
||||
const lastTwoUserMessages = openAiMessages.filter((msg) => msg.role === "user").slice(-2)
|
||||
lastTwoUserMessages.forEach((msg) => {
|
||||
if (typeof msg.content === "string") {
|
||||
msg.content = [{ type: "text", text: msg.content }]
|
||||
}
|
||||
if (Array.isArray(msg.content)) {
|
||||
let lastTextPart = msg.content.filter((part) => part.type === "text").pop()
|
||||
|
||||
if (!lastTextPart) {
|
||||
lastTextPart = { type: "text", text: "..." }
|
||||
msg.content.push(lastTextPart)
|
||||
}
|
||||
// @ts-ignore-next-line
|
||||
lastTextPart["cache_control"] = { type: "ephemeral" }
|
||||
}
|
||||
})
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
// Convert Anthropic tools to OpenAI tools
|
||||
const openAiTools: OpenAI.Chat.ChatCompletionTool[] = tools.map((tool) => ({
|
||||
type: "function",
|
||||
function: {
|
||||
name: tool.name,
|
||||
description: tool.description,
|
||||
parameters: tool.input_schema, // matches anthropic tool input schema (see https://platform.openai.com/docs/guides/function-calling)
|
||||
},
|
||||
}))
|
||||
|
||||
let createParams: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming
|
||||
|
||||
switch (this.getModel().id) {
|
||||
case "openai/o1-preview":
|
||||
case "openai/o1-mini":
|
||||
createParams = {
|
||||
model: this.getModel().id,
|
||||
max_tokens: this.getModel().info.maxTokens,
|
||||
messages: convertToO1Messages(convertToOpenAiMessages(messages), systemPrompt),
|
||||
}
|
||||
break
|
||||
default:
|
||||
createParams = {
|
||||
model: this.getModel().id,
|
||||
max_tokens: this.getModel().info.maxTokens,
|
||||
messages: openAiMessages,
|
||||
tools: openAiTools,
|
||||
tool_choice: "auto",
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
let completion: OpenAI.Chat.Completions.ChatCompletion
|
||||
try {
|
||||
completion = await this.client.chat.completions.create(createParams)
|
||||
} catch (error) {
|
||||
console.error("Error creating message from normal request. Using streaming fallback...", error)
|
||||
completion = await this.streamCompletion(createParams)
|
||||
}
|
||||
|
||||
const errorMessage = (completion as any).error?.message // openrouter returns an error object instead of the openai sdk throwing an error
|
||||
if (errorMessage) {
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
|
||||
let anthropicMessage: Anthropic.Messages.Message
|
||||
switch (this.getModel().id) {
|
||||
case "openai/o1-preview":
|
||||
case "openai/o1-mini":
|
||||
anthropicMessage = convertO1ResponseToAnthropicMessage(completion)
|
||||
break
|
||||
default:
|
||||
anthropicMessage = convertToAnthropicMessage(completion)
|
||||
break
|
||||
}
|
||||
|
||||
// Check if the model is Gemini Flash and remove extra escapes in tool result args
|
||||
// switch (this.getModel().id) {
|
||||
// case "google/gemini-pro-1.5":
|
||||
// case "google/gemini-flash-1.5":
|
||||
// const content = anthropicMessage.content
|
||||
// for (const block of content) {
|
||||
// if (
|
||||
// block.type === "tool_use" &&
|
||||
// typeof block.input === "object" &&
|
||||
// block.input !== null &&
|
||||
// "content" in block.input &&
|
||||
// typeof block.input.content === "string"
|
||||
// ) {
|
||||
// block.input.content = unescapeGeminiContent(block.input.content)
|
||||
// }
|
||||
// }
|
||||
// break
|
||||
// default:
|
||||
// break
|
||||
// }
|
||||
|
||||
const genId = completion.id
|
||||
// Log the generation details from OpenRouter API
|
||||
try {
|
||||
const response = await axios.get(`https://openrouter.ai/api/v1/generation?id=${genId}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${this.options.openRouterApiKey}`,
|
||||
},
|
||||
})
|
||||
// @ts-ignore-next-line
|
||||
anthropicMessage.usage.total_cost = response.data?.data?.total_cost
|
||||
console.log("OpenRouter generation details:", response.data)
|
||||
} catch (error) {
|
||||
console.error("Error fetching OpenRouter generation details:", error)
|
||||
}
|
||||
|
||||
return { message: anthropicMessage }
|
||||
}
|
||||
|
||||
/*
|
||||
Streaming the completion is a fallback behavior for when a normal request responds with an invalid JSON object ("Unexpected end of JSON input"). This would usually happen in cases where the model makes tool calls with large arguments. After talking with OpenRouter folks, streaming mitigates this issue for now until they fix the underlying problem ("some weird data from anthropic got decoded wrongly and crashed the buffer")
|
||||
*/
|
||||
async streamCompletion(
|
||||
createParams: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming
|
||||
): Promise<OpenAI.Chat.Completions.ChatCompletion> {
|
||||
const stream = await this.client.chat.completions.create({
|
||||
...createParams,
|
||||
stream: true,
|
||||
})
|
||||
|
||||
let textContent: string = ""
|
||||
let toolCalls: OpenAI.Chat.ChatCompletionMessageToolCall[] = []
|
||||
|
||||
try {
|
||||
let currentToolCall: (OpenAI.Chat.ChatCompletionMessageToolCall & { index?: number }) | null = null
|
||||
for await (const chunk of stream) {
|
||||
const delta = chunk.choices[0]?.delta
|
||||
if (delta?.content) {
|
||||
textContent += delta.content
|
||||
}
|
||||
if (delta?.tool_calls) {
|
||||
for (const toolCallDelta of delta.tool_calls) {
|
||||
if (toolCallDelta.index === undefined) {
|
||||
continue
|
||||
}
|
||||
if (!currentToolCall || currentToolCall.index !== toolCallDelta.index) {
|
||||
// new index means new tool call, so add the previous one to the list
|
||||
if (currentToolCall) {
|
||||
toolCalls.push(currentToolCall)
|
||||
}
|
||||
currentToolCall = {
|
||||
index: toolCallDelta.index,
|
||||
id: toolCallDelta.id || "",
|
||||
type: "function",
|
||||
function: { name: "", arguments: "" },
|
||||
}
|
||||
}
|
||||
if (toolCallDelta.id) {
|
||||
currentToolCall.id = toolCallDelta.id
|
||||
}
|
||||
if (toolCallDelta.type) {
|
||||
currentToolCall.type = toolCallDelta.type
|
||||
}
|
||||
if (toolCallDelta.function) {
|
||||
if (toolCallDelta.function.name) {
|
||||
currentToolCall.function.name = toolCallDelta.function.name
|
||||
}
|
||||
if (toolCallDelta.function.arguments) {
|
||||
currentToolCall.function.arguments =
|
||||
(currentToolCall.function.arguments || "") + toolCallDelta.function.arguments
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentToolCall) {
|
||||
toolCalls.push(currentToolCall)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error streaming completion:", error)
|
||||
throw error
|
||||
}
|
||||
|
||||
// Usage information is not available in streaming responses, so we need to estimate token counts
|
||||
function approximateTokenCount(text: string): number {
|
||||
return Math.ceil(new TextEncoder().encode(text).length / 4)
|
||||
}
|
||||
const promptTokens = approximateTokenCount(
|
||||
createParams.messages
|
||||
.map((m) => (typeof m.content === "string" ? m.content : JSON.stringify(m.content)))
|
||||
.join(" ")
|
||||
)
|
||||
const completionTokens = approximateTokenCount(
|
||||
textContent + toolCalls.map((toolCall) => toolCall.function.arguments || "").join(" ")
|
||||
)
|
||||
|
||||
const completion: OpenAI.Chat.Completions.ChatCompletion = {
|
||||
created: Date.now(),
|
||||
object: "chat.completion",
|
||||
id: `openrouter-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`, // this ID won't be traceable back to OpenRouter's systems if you need to debug issues
|
||||
choices: [
|
||||
{
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: textContent,
|
||||
tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
|
||||
refusal: null,
|
||||
},
|
||||
finish_reason: toolCalls.length > 0 ? "tool_calls" : "stop",
|
||||
index: 0,
|
||||
logprobs: null,
|
||||
},
|
||||
],
|
||||
model: this.getModel().id,
|
||||
usage: {
|
||||
prompt_tokens: promptTokens,
|
||||
completion_tokens: completionTokens,
|
||||
total_tokens: promptTokens + completionTokens,
|
||||
},
|
||||
}
|
||||
|
||||
return completion
|
||||
}
|
||||
|
||||
getModel(): { id: OpenRouterModelId; info: ModelInfo } {
|
||||
const modelId = this.options.apiModelId
|
||||
if (modelId && modelId in openRouterModels) {
|
||||
const id = modelId as OpenRouterModelId
|
||||
return { id, info: openRouterModels[id] }
|
||||
}
|
||||
return { id: openRouterDefaultModelId, info: openRouterModels[openRouterDefaultModelId] }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { Stream as AnthropicStream } from "@anthropic-ai/sdk/streaming"
|
||||
import { anthropicDefaultModelId, AnthropicModelId, anthropicModels, ApiHandlerOptions, ModelInfo } from "../../shared/api"
|
||||
import { ApiHandler } from "../index"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
|
||||
export class AnthropicHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: Anthropic
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new Anthropic({
|
||||
apiKey: this.options.apiKey,
|
||||
baseURL: this.options.anthropicBaseUrl || undefined,
|
||||
})
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
const model = this.getModel()
|
||||
let stream: AnthropicStream<Anthropic.Beta.PromptCaching.Messages.RawPromptCachingBetaMessageStreamEvent>
|
||||
const modelId = model.id
|
||||
switch (modelId) {
|
||||
// 'latest' alias does not support cache_control
|
||||
case "claude-3-5-sonnet-20241022":
|
||||
case "claude-3-5-haiku-20241022":
|
||||
case "claude-3-opus-20240229":
|
||||
case "claude-3-haiku-20240307": {
|
||||
/*
|
||||
The latest message will be the new user message, one before will be the assistant message from a previous request, and the user message before that will be a previously cached user message. So we need to mark the latest user message as ephemeral to cache it for the next request, and mark the second to last user message as ephemeral to let the server know the last message to retrieve from the cache for the current request..
|
||||
*/
|
||||
const userMsgIndices = messages.reduce(
|
||||
(acc, msg, index) => (msg.role === "user" ? [...acc, index] : acc),
|
||||
[] as number[],
|
||||
)
|
||||
const lastUserMsgIndex = userMsgIndices[userMsgIndices.length - 1] ?? -1
|
||||
const secondLastMsgUserIndex = userMsgIndices[userMsgIndices.length - 2] ?? -1
|
||||
stream = await this.client.beta.promptCaching.messages.create(
|
||||
{
|
||||
model: modelId,
|
||||
max_tokens: model.info.maxTokens || 8192,
|
||||
temperature: 0,
|
||||
system: [
|
||||
{
|
||||
text: systemPrompt,
|
||||
type: "text",
|
||||
cache_control: { type: "ephemeral" },
|
||||
},
|
||||
], // setting cache breakpoint for system prompt so new tasks can reuse it
|
||||
messages: messages.map((message, index) => {
|
||||
if (index === lastUserMsgIndex || index === secondLastMsgUserIndex) {
|
||||
return {
|
||||
...message,
|
||||
content:
|
||||
typeof message.content === "string"
|
||||
? [
|
||||
{
|
||||
type: "text",
|
||||
text: message.content,
|
||||
cache_control: {
|
||||
type: "ephemeral",
|
||||
},
|
||||
},
|
||||
]
|
||||
: message.content.map((content, contentIndex) =>
|
||||
contentIndex === message.content.length - 1
|
||||
? {
|
||||
...content,
|
||||
cache_control: {
|
||||
type: "ephemeral",
|
||||
},
|
||||
}
|
||||
: content,
|
||||
),
|
||||
}
|
||||
}
|
||||
return message
|
||||
}),
|
||||
// tools, // cache breakpoints go from tools > system > messages, and since tools dont change, we can just set the breakpoint at the end of system (this avoids having to set a breakpoint at the end of tools which by itself does not meet min requirements for haiku caching)
|
||||
// tool_choice: { type: "auto" },
|
||||
// tools: tools,
|
||||
stream: true,
|
||||
},
|
||||
(() => {
|
||||
// prompt caching: https://x.com/alexalbert__/status/1823751995901272068
|
||||
// https://github.com/anthropics/anthropic-sdk-typescript?tab=readme-ov-file#default-headers
|
||||
// https://github.com/anthropics/anthropic-sdk-typescript/commit/c920b77fc67bd839bfeb6716ceab9d7c9bbe7393
|
||||
switch (modelId) {
|
||||
case "claude-3-5-sonnet-20241022":
|
||||
case "claude-3-5-haiku-20241022":
|
||||
case "claude-3-opus-20240229":
|
||||
case "claude-3-haiku-20240307":
|
||||
return {
|
||||
headers: {
|
||||
"anthropic-beta": "prompt-caching-2024-07-31",
|
||||
},
|
||||
}
|
||||
default:
|
||||
return undefined
|
||||
}
|
||||
})(),
|
||||
)
|
||||
break
|
||||
}
|
||||
default: {
|
||||
stream = (await this.client.messages.create({
|
||||
model: modelId,
|
||||
max_tokens: model.info.maxTokens || 8192,
|
||||
temperature: 0,
|
||||
system: [{ text: systemPrompt, type: "text" }],
|
||||
messages,
|
||||
// tools,
|
||||
// tool_choice: { type: "auto" },
|
||||
stream: true,
|
||||
})) as any
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for await (const chunk of stream) {
|
||||
switch (chunk.type) {
|
||||
case "message_start":
|
||||
// tells us cache reads/writes/input/output
|
||||
const usage = chunk.message.usage
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: usage.input_tokens || 0,
|
||||
outputTokens: usage.output_tokens || 0,
|
||||
cacheWriteTokens: usage.cache_creation_input_tokens || undefined,
|
||||
cacheReadTokens: usage.cache_read_input_tokens || undefined,
|
||||
}
|
||||
break
|
||||
case "message_delta":
|
||||
// tells us stop_reason, stop_sequence, and output tokens along the way and at the end of the message
|
||||
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: 0,
|
||||
outputTokens: chunk.usage.output_tokens || 0,
|
||||
}
|
||||
break
|
||||
case "message_stop":
|
||||
// no usage data, just an indicator that the message is done
|
||||
break
|
||||
case "content_block_start":
|
||||
switch (chunk.content_block.type) {
|
||||
case "text":
|
||||
// we may receive multiple text blocks, in which case just insert a line break between them
|
||||
if (chunk.index > 0) {
|
||||
yield {
|
||||
type: "text",
|
||||
text: "\n",
|
||||
}
|
||||
}
|
||||
yield {
|
||||
type: "text",
|
||||
text: chunk.content_block.text,
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
case "content_block_delta":
|
||||
switch (chunk.delta.type) {
|
||||
case "text_delta":
|
||||
yield {
|
||||
type: "text",
|
||||
text: chunk.delta.text,
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
case "content_block_stop":
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): { id: AnthropicModelId; info: ModelInfo } {
|
||||
const modelId = this.options.apiModelId
|
||||
if (modelId && modelId in anthropicModels) {
|
||||
const id = modelId as AnthropicModelId
|
||||
return { id, info: anthropicModels[id] }
|
||||
}
|
||||
return {
|
||||
id: anthropicDefaultModelId,
|
||||
info: anthropicModels[anthropicDefaultModelId],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import AnthropicBedrock from "@anthropic-ai/bedrock-sdk"
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { ApiHandler } from "../"
|
||||
import { ApiHandlerOptions, bedrockDefaultModelId, BedrockModelId, bedrockModels, ModelInfo } from "../../shared/api"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
|
||||
// https://docs.anthropic.com/en/api/claude-on-amazon-bedrock
|
||||
export class AwsBedrockHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: AnthropicBedrock
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new AnthropicBedrock({
|
||||
// Authenticate by either providing the keys below or use the default AWS credential providers, such as
|
||||
// using ~/.aws/credentials or the "AWS_SECRET_ACCESS_KEY" and "AWS_ACCESS_KEY_ID" environment variables.
|
||||
...(this.options.awsAccessKey ? { awsAccessKey: this.options.awsAccessKey } : {}),
|
||||
...(this.options.awsSecretKey ? { awsSecretKey: this.options.awsSecretKey } : {}),
|
||||
...(this.options.awsSessionToken ? { awsSessionToken: this.options.awsSessionToken } : {}),
|
||||
|
||||
// awsRegion changes the aws region to which the request is made. By default, we read AWS_REGION,
|
||||
// and if that's not present, we default to us-east-1. Note that we do not read ~/.aws/config for the region.
|
||||
awsRegion: this.options.awsRegion,
|
||||
})
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
// cross region inference requires prefixing the model id with the region
|
||||
let modelId: string
|
||||
if (this.options.awsUseCrossRegionInference) {
|
||||
let regionPrefix = (this.options.awsRegion || "").slice(0, 3)
|
||||
switch (regionPrefix) {
|
||||
case "us-":
|
||||
modelId = `us.${this.getModel().id}`
|
||||
break
|
||||
case "eu-":
|
||||
modelId = `eu.${this.getModel().id}`
|
||||
break
|
||||
default:
|
||||
// cross region inference is not supported in this region, falling back to default model
|
||||
modelId = this.getModel().id
|
||||
break
|
||||
}
|
||||
} else {
|
||||
modelId = this.getModel().id
|
||||
}
|
||||
|
||||
const stream = await this.client.messages.create({
|
||||
model: modelId,
|
||||
max_tokens: this.getModel().info.maxTokens || 8192,
|
||||
temperature: 0,
|
||||
system: systemPrompt,
|
||||
messages,
|
||||
stream: true,
|
||||
})
|
||||
for await (const chunk of stream) {
|
||||
switch (chunk.type) {
|
||||
case "message_start":
|
||||
const usage = chunk.message.usage
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: usage.input_tokens || 0,
|
||||
outputTokens: usage.output_tokens || 0,
|
||||
}
|
||||
break
|
||||
case "message_delta":
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: 0,
|
||||
outputTokens: chunk.usage.output_tokens || 0,
|
||||
}
|
||||
break
|
||||
|
||||
case "content_block_start":
|
||||
switch (chunk.content_block.type) {
|
||||
case "text":
|
||||
if (chunk.index > 0) {
|
||||
yield {
|
||||
type: "text",
|
||||
text: "\n",
|
||||
}
|
||||
}
|
||||
yield {
|
||||
type: "text",
|
||||
text: chunk.content_block.text,
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
case "content_block_delta":
|
||||
switch (chunk.delta.type) {
|
||||
case "text_delta":
|
||||
yield {
|
||||
type: "text",
|
||||
text: chunk.delta.text,
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): { id: BedrockModelId; info: ModelInfo } {
|
||||
const modelId = this.options.apiModelId
|
||||
if (modelId && modelId in bedrockModels) {
|
||||
const id = modelId as BedrockModelId
|
||||
return { id, info: bedrockModels[id] }
|
||||
}
|
||||
return {
|
||||
id: bedrockDefaultModelId,
|
||||
info: bedrockModels[bedrockDefaultModelId],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import OpenAI from "openai"
|
||||
import { ApiHandler } from "../"
|
||||
import { ApiHandlerOptions, DeepSeekModelId, ModelInfo, deepSeekDefaultModelId, deepSeekModels } from "../../shared/api"
|
||||
import { convertToOpenAiMessages } from "../transform/openai-format"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
|
||||
export class DeepSeekHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: OpenAI
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new OpenAI({
|
||||
baseURL: "https://api.deepseek.com/v1",
|
||||
apiKey: this.options.deepSeekApiKey,
|
||||
})
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
const model = this.getModel()
|
||||
const stream = await this.client.chat.completions.create({
|
||||
model: model.id,
|
||||
max_completion_tokens: model.info.maxTokens,
|
||||
messages: [{ role: "system", content: systemPrompt }, ...convertToOpenAiMessages(messages)],
|
||||
stream: true,
|
||||
stream_options: { include_usage: true },
|
||||
// Only set temperature for non-reasoner models
|
||||
...(model.id === "deepseek-reasoner" ? {} : { temperature: 0 }),
|
||||
})
|
||||
|
||||
for await (const chunk of stream) {
|
||||
const delta = chunk.choices[0]?.delta
|
||||
if (delta?.content) {
|
||||
yield {
|
||||
type: "text",
|
||||
text: delta.content,
|
||||
}
|
||||
}
|
||||
|
||||
if (chunk.usage) {
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: chunk.usage.prompt_tokens || 0, // (deepseek reports total input AND cache reads/writes, see context caching: https://api-docs.deepseek.com/guides/kv_cache) where the input tokens is the sum of the cache hits/misses, while anthropic reports them as separate tokens. This is important to know for 1) context management truncation algorithm, and 2) cost calculation (NOTE: we report both input and cache stats but for now set input price to 0 since all the cost calculation will be done using cache hits/misses)
|
||||
outputTokens: chunk.usage.completion_tokens || 0,
|
||||
// @ts-ignore-next-line
|
||||
cacheReadTokens: chunk.usage.prompt_cache_hit_tokens || 0,
|
||||
// @ts-ignore-next-line
|
||||
cacheWriteTokens: chunk.usage.prompt_cache_miss_tokens || 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): { id: DeepSeekModelId; info: ModelInfo } {
|
||||
const modelId = this.options.apiModelId
|
||||
if (modelId && modelId in deepSeekModels) {
|
||||
const id = modelId as DeepSeekModelId
|
||||
return { id, info: deepSeekModels[id] }
|
||||
}
|
||||
return {
|
||||
id: deepSeekDefaultModelId,
|
||||
info: deepSeekModels[deepSeekDefaultModelId],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { GoogleGenerativeAI } from "@google/generative-ai"
|
||||
import { ApiHandler } from "../"
|
||||
import { ApiHandlerOptions, geminiDefaultModelId, GeminiModelId, geminiModels, ModelInfo } from "../../shared/api"
|
||||
import { convertAnthropicMessageToGemini } from "../transform/gemini-format"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
|
||||
export class GeminiHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: GoogleGenerativeAI
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
if (!options.geminiApiKey) {
|
||||
throw new Error("API key is required for Google Gemini")
|
||||
}
|
||||
this.options = options
|
||||
this.client = new GoogleGenerativeAI(options.geminiApiKey)
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
const model = this.client.getGenerativeModel({
|
||||
model: this.getModel().id,
|
||||
systemInstruction: systemPrompt,
|
||||
})
|
||||
const result = await model.generateContentStream({
|
||||
contents: messages.map(convertAnthropicMessageToGemini),
|
||||
generationConfig: {
|
||||
// maxOutputTokens: this.getModel().info.maxTokens,
|
||||
temperature: 0,
|
||||
},
|
||||
})
|
||||
|
||||
for await (const chunk of result.stream) {
|
||||
yield {
|
||||
type: "text",
|
||||
text: chunk.text(),
|
||||
}
|
||||
}
|
||||
|
||||
const response = await result.response
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: response.usageMetadata?.promptTokenCount ?? 0,
|
||||
outputTokens: response.usageMetadata?.candidatesTokenCount ?? 0,
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): { id: GeminiModelId; info: ModelInfo } {
|
||||
const modelId = this.options.apiModelId
|
||||
if (modelId && modelId in geminiModels) {
|
||||
const id = modelId as GeminiModelId
|
||||
return { id, info: geminiModels[id] }
|
||||
}
|
||||
return {
|
||||
id: geminiDefaultModelId,
|
||||
info: geminiModels[geminiDefaultModelId],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import OpenAI from "openai"
|
||||
import { ApiHandler } from "../"
|
||||
import { ApiHandlerOptions, ModelInfo, openAiModelInfoSaneDefaults } from "../../shared/api"
|
||||
import { convertToOpenAiMessages } from "../transform/openai-format"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
|
||||
export class LmStudioHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: OpenAI
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new OpenAI({
|
||||
baseURL: (this.options.lmStudioBaseUrl || "http://localhost:1234") + "/v1",
|
||||
apiKey: "noop",
|
||||
})
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
|
||||
{ role: "system", content: systemPrompt },
|
||||
...convertToOpenAiMessages(messages),
|
||||
]
|
||||
|
||||
try {
|
||||
const stream = await this.client.chat.completions.create({
|
||||
model: this.getModel().id,
|
||||
messages: openAiMessages,
|
||||
temperature: 0,
|
||||
stream: true,
|
||||
})
|
||||
for await (const chunk of stream) {
|
||||
const delta = chunk.choices[0]?.delta
|
||||
if (delta?.content) {
|
||||
yield {
|
||||
type: "text",
|
||||
text: delta.content,
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// LM Studio doesn't return an error code/body for now
|
||||
throw new Error(
|
||||
"Please check the LM Studio developer logs to debug what went wrong. You may need to load the model with a larger context length to work with Cline's prompts.",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): { id: string; info: ModelInfo } {
|
||||
return {
|
||||
id: this.options.lmStudioModelId || "",
|
||||
info: openAiModelInfoSaneDefaults,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { Mistral } from "@mistralai/mistralai"
|
||||
import { ApiHandler } from "../"
|
||||
import {
|
||||
ApiHandlerOptions,
|
||||
mistralDefaultModelId,
|
||||
MistralModelId,
|
||||
mistralModels,
|
||||
ModelInfo,
|
||||
openAiNativeDefaultModelId,
|
||||
OpenAiNativeModelId,
|
||||
openAiNativeModels,
|
||||
} from "../../shared/api"
|
||||
import { convertToMistralMessages } from "../transform/mistral-format"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
|
||||
export class MistralHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: Mistral
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new Mistral({
|
||||
serverURL: "https://codestral.mistral.ai",
|
||||
apiKey: this.options.mistralApiKey,
|
||||
})
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
const stream = await this.client.chat.stream({
|
||||
model: this.getModel().id,
|
||||
// max_completion_tokens: this.getModel().info.maxTokens,
|
||||
temperature: 0,
|
||||
messages: [{ role: "system", content: systemPrompt }, ...convertToMistralMessages(messages)],
|
||||
stream: true,
|
||||
})
|
||||
|
||||
for await (const chunk of stream) {
|
||||
const delta = chunk.data.choices[0]?.delta
|
||||
if (delta?.content) {
|
||||
let content: string = ""
|
||||
if (typeof delta.content === "string") {
|
||||
content = delta.content
|
||||
} else if (Array.isArray(delta.content)) {
|
||||
content = delta.content.map((c) => (c.type === "text" ? c.text : "")).join("")
|
||||
}
|
||||
yield {
|
||||
type: "text",
|
||||
text: content,
|
||||
}
|
||||
}
|
||||
|
||||
if (chunk.data.usage) {
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: chunk.data.usage.promptTokens || 0,
|
||||
outputTokens: chunk.data.usage.completionTokens || 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): { id: MistralModelId; info: ModelInfo } {
|
||||
const modelId = this.options.apiModelId
|
||||
if (modelId && modelId in mistralModels) {
|
||||
const id = modelId as MistralModelId
|
||||
return { id, info: mistralModels[id] }
|
||||
}
|
||||
return {
|
||||
id: mistralDefaultModelId,
|
||||
info: mistralModels[mistralDefaultModelId],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import OpenAI from "openai"
|
||||
import { ApiHandler } from "../"
|
||||
import { ApiHandlerOptions, ModelInfo, openAiModelInfoSaneDefaults } from "../../shared/api"
|
||||
import { convertToOpenAiMessages } from "../transform/openai-format"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
|
||||
export class OllamaHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: OpenAI
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new OpenAI({
|
||||
baseURL: (this.options.ollamaBaseUrl || "http://localhost:11434") + "/v1",
|
||||
apiKey: "ollama",
|
||||
})
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
|
||||
{ role: "system", content: systemPrompt },
|
||||
...convertToOpenAiMessages(messages),
|
||||
]
|
||||
|
||||
const stream = await this.client.chat.completions.create({
|
||||
model: this.getModel().id,
|
||||
messages: openAiMessages,
|
||||
temperature: 0,
|
||||
stream: true,
|
||||
})
|
||||
for await (const chunk of stream) {
|
||||
const delta = chunk.choices[0]?.delta
|
||||
if (delta?.content) {
|
||||
yield {
|
||||
type: "text",
|
||||
text: delta.content,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): { id: string; info: ModelInfo } {
|
||||
return {
|
||||
id: this.options.ollamaModelId || "",
|
||||
info: openAiModelInfoSaneDefaults,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import OpenAI from "openai"
|
||||
import { ApiHandler } from "../"
|
||||
import {
|
||||
ApiHandlerOptions,
|
||||
ModelInfo,
|
||||
openAiNativeDefaultModelId,
|
||||
OpenAiNativeModelId,
|
||||
openAiNativeModels,
|
||||
} from "../../shared/api"
|
||||
import { convertToOpenAiMessages } from "../transform/openai-format"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
|
||||
export class OpenAiNativeHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: OpenAI
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new OpenAI({
|
||||
apiKey: this.options.openAiNativeApiKey,
|
||||
})
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
switch (this.getModel().id) {
|
||||
case "o1":
|
||||
case "o1-preview":
|
||||
case "o1-mini": {
|
||||
// o1 doesnt support streaming, non-1 temp, or system prompt
|
||||
const response = await this.client.chat.completions.create({
|
||||
model: this.getModel().id,
|
||||
messages: [{ role: "user", content: systemPrompt }, ...convertToOpenAiMessages(messages)],
|
||||
})
|
||||
yield {
|
||||
type: "text",
|
||||
text: response.choices[0]?.message.content || "",
|
||||
}
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: response.usage?.prompt_tokens || 0,
|
||||
outputTokens: response.usage?.completion_tokens || 0,
|
||||
}
|
||||
break
|
||||
}
|
||||
default: {
|
||||
const stream = await this.client.chat.completions.create({
|
||||
model: this.getModel().id,
|
||||
// max_completion_tokens: this.getModel().info.maxTokens,
|
||||
temperature: 0,
|
||||
messages: [{ role: "system", content: systemPrompt }, ...convertToOpenAiMessages(messages)],
|
||||
stream: true,
|
||||
stream_options: { include_usage: true },
|
||||
})
|
||||
|
||||
for await (const chunk of stream) {
|
||||
const delta = chunk.choices[0]?.delta
|
||||
if (delta?.content) {
|
||||
yield {
|
||||
type: "text",
|
||||
text: delta.content,
|
||||
}
|
||||
}
|
||||
|
||||
// contains a null value except for the last chunk which contains the token usage statistics for the entire request
|
||||
if (chunk.usage) {
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: chunk.usage.prompt_tokens || 0,
|
||||
outputTokens: chunk.usage.completion_tokens || 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): { id: OpenAiNativeModelId; info: ModelInfo } {
|
||||
const modelId = this.options.apiModelId
|
||||
if (modelId && modelId in openAiNativeModels) {
|
||||
const id = modelId as OpenAiNativeModelId
|
||||
return { id, info: openAiNativeModels[id] }
|
||||
}
|
||||
return {
|
||||
id: openAiNativeDefaultModelId,
|
||||
info: openAiNativeModels[openAiNativeDefaultModelId],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import OpenAI, { AzureOpenAI } from "openai"
|
||||
import { ApiHandlerOptions, azureOpenAiDefaultApiVersion, ModelInfo, openAiModelInfoSaneDefaults } from "../../shared/api"
|
||||
import { ApiHandler } from "../index"
|
||||
import { convertToOpenAiMessages } from "../transform/openai-format"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
|
||||
export class OpenAiHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: OpenAI
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
// Azure API shape slightly differs from the core API shape: https://github.com/openai/openai-node?tab=readme-ov-file#microsoft-azure-openai
|
||||
if (this.options.openAiBaseUrl?.toLowerCase().includes("azure.com")) {
|
||||
this.client = new AzureOpenAI({
|
||||
baseURL: this.options.openAiBaseUrl,
|
||||
apiKey: this.options.openAiApiKey,
|
||||
apiVersion: this.options.azureApiVersion || azureOpenAiDefaultApiVersion,
|
||||
})
|
||||
} else {
|
||||
this.client = new OpenAI({
|
||||
baseURL: this.options.openAiBaseUrl,
|
||||
apiKey: this.options.openAiApiKey,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
|
||||
{ role: "system", content: systemPrompt },
|
||||
...convertToOpenAiMessages(messages),
|
||||
]
|
||||
const stream = await this.client.chat.completions.create({
|
||||
model: this.options.openAiModelId ?? "",
|
||||
messages: openAiMessages,
|
||||
temperature: 0,
|
||||
stream: true,
|
||||
stream_options: { include_usage: true },
|
||||
})
|
||||
for await (const chunk of stream) {
|
||||
const delta = chunk.choices[0]?.delta
|
||||
if (delta?.content) {
|
||||
yield {
|
||||
type: "text",
|
||||
text: delta.content,
|
||||
}
|
||||
}
|
||||
if (chunk.usage) {
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: chunk.usage.prompt_tokens || 0,
|
||||
outputTokens: chunk.usage.completion_tokens || 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): { id: string; info: ModelInfo } {
|
||||
return {
|
||||
id: this.options.openAiModelId ?? "",
|
||||
info: openAiModelInfoSaneDefaults,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import axios from "axios"
|
||||
import OpenAI from "openai"
|
||||
import { ApiHandler } from "../"
|
||||
import { ApiHandlerOptions, ModelInfo, openRouterDefaultModelId, openRouterDefaultModelInfo } from "../../shared/api"
|
||||
import { convertToOpenAiMessages } from "../transform/openai-format"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
import delay from "delay"
|
||||
|
||||
export class OpenRouterHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: OpenAI
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new OpenAI({
|
||||
baseURL: "https://openrouter.ai/api/v1",
|
||||
apiKey: this.options.openRouterApiKey,
|
||||
defaultHeaders: {
|
||||
"HTTP-Referer": "https://cline.bot", // Optional, for including your app on openrouter.ai rankings.
|
||||
"X-Title": "Cline", // Optional. Shows in rankings on openrouter.ai.
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
const model = this.getModel()
|
||||
|
||||
// Convert Anthropic messages to OpenAI format
|
||||
const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
|
||||
{ role: "system", content: systemPrompt },
|
||||
...convertToOpenAiMessages(messages),
|
||||
]
|
||||
|
||||
// prompt caching: https://openrouter.ai/docs/prompt-caching
|
||||
// this is specifically for claude models (some models may 'support prompt caching' automatically without this)
|
||||
switch (model.id) {
|
||||
case "anthropic/claude-3.5-sonnet":
|
||||
case "anthropic/claude-3.5-sonnet:beta":
|
||||
case "anthropic/claude-3.5-sonnet-20240620":
|
||||
case "anthropic/claude-3.5-sonnet-20240620:beta":
|
||||
case "anthropic/claude-3-5-haiku":
|
||||
case "anthropic/claude-3-5-haiku:beta":
|
||||
case "anthropic/claude-3-5-haiku-20241022":
|
||||
case "anthropic/claude-3-5-haiku-20241022:beta":
|
||||
case "anthropic/claude-3-haiku":
|
||||
case "anthropic/claude-3-haiku:beta":
|
||||
case "anthropic/claude-3-opus":
|
||||
case "anthropic/claude-3-opus:beta":
|
||||
openAiMessages[0] = {
|
||||
role: "system",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: systemPrompt,
|
||||
// @ts-ignore-next-line
|
||||
cache_control: { type: "ephemeral" },
|
||||
},
|
||||
],
|
||||
}
|
||||
// Add cache_control to the last two user messages
|
||||
// (note: this works because we only ever add one user message at a time, but if we added multiple we'd need to mark the user message before the last assistant message)
|
||||
const lastTwoUserMessages = openAiMessages.filter((msg) => msg.role === "user").slice(-2)
|
||||
lastTwoUserMessages.forEach((msg) => {
|
||||
if (typeof msg.content === "string") {
|
||||
msg.content = [{ type: "text", text: msg.content }]
|
||||
}
|
||||
if (Array.isArray(msg.content)) {
|
||||
// NOTE: this is fine since env details will always be added at the end. but if it weren't there, and the user added a image_url type message, it would pop a text part before it and then move it after to the end.
|
||||
let lastTextPart = msg.content.filter((part) => part.type === "text").pop()
|
||||
|
||||
if (!lastTextPart) {
|
||||
lastTextPart = { type: "text", text: "..." }
|
||||
msg.content.push(lastTextPart)
|
||||
}
|
||||
// @ts-ignore-next-line
|
||||
lastTextPart["cache_control"] = { type: "ephemeral" }
|
||||
}
|
||||
})
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
// Not sure how openrouter defaults max tokens when no value is provided, but the anthropic api requires this value and since they offer both 4096 and 8192 variants, we should ensure 8192.
|
||||
// (models usually default to max tokens allowed)
|
||||
let maxTokens: number | undefined
|
||||
switch (model.id) {
|
||||
case "anthropic/claude-3.5-sonnet":
|
||||
case "anthropic/claude-3.5-sonnet:beta":
|
||||
case "anthropic/claude-3.5-sonnet-20240620":
|
||||
case "anthropic/claude-3.5-sonnet-20240620:beta":
|
||||
case "anthropic/claude-3-5-haiku":
|
||||
case "anthropic/claude-3-5-haiku:beta":
|
||||
case "anthropic/claude-3-5-haiku-20241022":
|
||||
case "anthropic/claude-3-5-haiku-20241022:beta":
|
||||
maxTokens = 8_192
|
||||
break
|
||||
}
|
||||
|
||||
// Removes messages in the middle when close to context window limit. Should not be applied to models that support prompt caching since it would continuously break the cache.
|
||||
let shouldApplyMiddleOutTransform = !model.info.supportsPromptCache
|
||||
// except for deepseek (which we set supportsPromptCache to true for), where because the context window is so small our truncation algo might miss and we should use openrouter's middle-out transform as a fallback to ensure we don't exceed the context window (FIXME: once we have a more robust token estimator we should not rely on this)
|
||||
if (model.id === "deepseek/deepseek-chat") {
|
||||
shouldApplyMiddleOutTransform = true
|
||||
}
|
||||
|
||||
// @ts-ignore-next-line
|
||||
const stream = await this.client.chat.completions.create({
|
||||
model: model.id,
|
||||
max_tokens: maxTokens,
|
||||
temperature: 0,
|
||||
messages: openAiMessages,
|
||||
stream: true,
|
||||
transforms: shouldApplyMiddleOutTransform ? ["middle-out"] : undefined,
|
||||
})
|
||||
|
||||
let genId: string | undefined
|
||||
|
||||
for await (const chunk of stream) {
|
||||
// openrouter returns an error object instead of the openai sdk throwing an error
|
||||
if ("error" in chunk) {
|
||||
const error = chunk.error as { message?: string; code?: number }
|
||||
console.error(`OpenRouter API Error: ${error?.code} - ${error?.message}`)
|
||||
throw new Error(`OpenRouter API Error ${error?.code}: ${error?.message}`)
|
||||
}
|
||||
|
||||
if (!genId && chunk.id) {
|
||||
genId = chunk.id
|
||||
}
|
||||
|
||||
const delta = chunk.choices[0]?.delta
|
||||
if (delta?.content) {
|
||||
yield {
|
||||
type: "text",
|
||||
text: delta.content,
|
||||
}
|
||||
}
|
||||
// if (chunk.usage) {
|
||||
// yield {
|
||||
// type: "usage",
|
||||
// inputTokens: chunk.usage.prompt_tokens || 0,
|
||||
// outputTokens: chunk.usage.completion_tokens || 0,
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
await delay(500) // FIXME: necessary delay to ensure generation endpoint is ready
|
||||
|
||||
try {
|
||||
const response = await axios.get(`https://openrouter.ai/api/v1/generation?id=${genId}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${this.options.openRouterApiKey}`,
|
||||
},
|
||||
timeout: 5_000, // this request hangs sometimes
|
||||
})
|
||||
|
||||
const generation = response.data?.data
|
||||
console.log("OpenRouter generation details:", response.data)
|
||||
yield {
|
||||
type: "usage",
|
||||
// cacheWriteTokens: 0,
|
||||
// cacheReadTokens: 0,
|
||||
// openrouter generation endpoint fails often
|
||||
inputTokens: generation?.native_tokens_prompt || 0,
|
||||
outputTokens: generation?.native_tokens_completion || 0,
|
||||
totalCost: generation?.total_cost || 0,
|
||||
}
|
||||
} catch (error) {
|
||||
// ignore if fails
|
||||
console.error("Error fetching OpenRouter generation details:", error)
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): { id: string; info: ModelInfo } {
|
||||
const modelId = this.options.openRouterModelId
|
||||
const modelInfo = this.options.openRouterModelInfo
|
||||
if (modelId && modelInfo) {
|
||||
return { id: modelId, info: modelInfo }
|
||||
}
|
||||
return {
|
||||
id: openRouterDefaultModelId,
|
||||
info: openRouterDefaultModelInfo,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { AnthropicVertex } from "@anthropic-ai/vertex-sdk"
|
||||
import { ApiHandler } from "../"
|
||||
import { ApiHandlerOptions, ModelInfo, vertexDefaultModelId, VertexModelId, vertexModels } from "../../shared/api"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
|
||||
// https://docs.anthropic.com/en/api/claude-on-vertex-ai
|
||||
export class VertexHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: AnthropicVertex
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new AnthropicVertex({
|
||||
projectId: this.options.vertexProjectId,
|
||||
// https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-claude#regions
|
||||
region: this.options.vertexRegion,
|
||||
})
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
const stream = await this.client.messages.create({
|
||||
model: this.getModel().id,
|
||||
max_tokens: this.getModel().info.maxTokens || 8192,
|
||||
temperature: 0,
|
||||
system: systemPrompt,
|
||||
messages,
|
||||
stream: true,
|
||||
})
|
||||
for await (const chunk of stream) {
|
||||
switch (chunk.type) {
|
||||
case "message_start":
|
||||
const usage = chunk.message.usage
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: usage.input_tokens || 0,
|
||||
outputTokens: usage.output_tokens || 0,
|
||||
}
|
||||
break
|
||||
case "message_delta":
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: 0,
|
||||
outputTokens: chunk.usage.output_tokens || 0,
|
||||
}
|
||||
break
|
||||
|
||||
case "content_block_start":
|
||||
switch (chunk.content_block.type) {
|
||||
case "text":
|
||||
if (chunk.index > 0) {
|
||||
yield {
|
||||
type: "text",
|
||||
text: "\n",
|
||||
}
|
||||
}
|
||||
yield {
|
||||
type: "text",
|
||||
text: chunk.content_block.text,
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
case "content_block_delta":
|
||||
switch (chunk.delta.type) {
|
||||
case "text_delta":
|
||||
yield {
|
||||
type: "text",
|
||||
text: chunk.delta.text,
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): { id: VertexModelId; info: ModelInfo } {
|
||||
const modelId = this.options.apiModelId
|
||||
if (modelId && modelId in vertexModels) {
|
||||
const id = modelId as VertexModelId
|
||||
return { id, info: vertexModels[id] }
|
||||
}
|
||||
return {
|
||||
id: vertexDefaultModelId,
|
||||
info: vertexModels[vertexDefaultModelId],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,639 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import * as vscode from "vscode"
|
||||
import { ApiHandler, SingleCompletionHandler } from "../"
|
||||
import { calculateApiCost } from "../../utils/cost"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
import { convertToVsCodeLmMessages } from "../transform/vscode-lm-format"
|
||||
import { SELECTOR_SEPARATOR, stringifyVsCodeLmModelSelector } from "../../shared/vsCodeSelectorUtils"
|
||||
import { ApiHandlerOptions, ModelInfo, openAiModelInfoSaneDefaults } from "../../shared/api"
|
||||
|
||||
// Cline does not update VSCode type definitions or engine requirements to maintain compatibility.
|
||||
// This declaration (as seen in src/integrations/TerminalManager.ts) provides types for the Language Model API in newer versions of VSCode.
|
||||
// Extracted from https://github.com/microsoft/vscode/blob/131ee0ef660d600cd0a7e6058375b281553abe20/src/vscode-dts/vscode.d.ts
|
||||
declare module "vscode" {
|
||||
enum LanguageModelChatMessageRole {
|
||||
User = 1,
|
||||
Assistant = 2,
|
||||
}
|
||||
enum LanguageModelChatToolMode {
|
||||
Auto = 1,
|
||||
Required = 2,
|
||||
}
|
||||
interface LanguageModelChatSelector {
|
||||
vendor?: string
|
||||
family?: string
|
||||
version?: string
|
||||
id?: string
|
||||
}
|
||||
interface LanguageModelChatTool {
|
||||
name: string
|
||||
description: string
|
||||
inputSchema?: object
|
||||
}
|
||||
interface LanguageModelChatRequestOptions {
|
||||
justification?: string
|
||||
modelOptions?: { [name: string]: any }
|
||||
tools?: LanguageModelChatTool[]
|
||||
toolMode?: LanguageModelChatToolMode
|
||||
}
|
||||
class LanguageModelTextPart {
|
||||
value: string
|
||||
constructor(value: string)
|
||||
}
|
||||
class LanguageModelToolCallPart {
|
||||
callId: string
|
||||
name: string
|
||||
input: object
|
||||
constructor(callId: string, name: string, input: object)
|
||||
}
|
||||
interface LanguageModelChatResponse {
|
||||
stream: AsyncIterable<LanguageModelTextPart | LanguageModelToolCallPart | unknown>
|
||||
text: AsyncIterable<string>
|
||||
}
|
||||
interface LanguageModelChat {
|
||||
readonly name: string
|
||||
readonly id: string
|
||||
readonly vendor: string
|
||||
readonly family: string
|
||||
readonly version: string
|
||||
readonly maxInputTokens: number
|
||||
|
||||
sendRequest(
|
||||
messages: LanguageModelChatMessage[],
|
||||
options?: LanguageModelChatRequestOptions,
|
||||
token?: CancellationToken,
|
||||
): Thenable<LanguageModelChatResponse>
|
||||
countTokens(text: string | LanguageModelChatMessage, token?: CancellationToken): Thenable<number>
|
||||
}
|
||||
class LanguageModelPromptTsxPart {
|
||||
value: unknown
|
||||
constructor(value: unknown)
|
||||
}
|
||||
class LanguageModelToolResultPart {
|
||||
callId: string
|
||||
content: Array<LanguageModelTextPart | LanguageModelPromptTsxPart | unknown>
|
||||
constructor(callId: string, content: Array<LanguageModelTextPart | LanguageModelPromptTsxPart | unknown>)
|
||||
}
|
||||
class LanguageModelChatMessage {
|
||||
static User(
|
||||
content: string | Array<LanguageModelTextPart | LanguageModelToolResultPart>,
|
||||
name?: string,
|
||||
): LanguageModelChatMessage
|
||||
static Assistant(
|
||||
content: string | Array<LanguageModelTextPart | LanguageModelToolCallPart>,
|
||||
name?: string,
|
||||
): LanguageModelChatMessage
|
||||
|
||||
role: LanguageModelChatMessageRole
|
||||
content: Array<LanguageModelTextPart | LanguageModelToolResultPart | LanguageModelToolCallPart>
|
||||
name: string | undefined
|
||||
|
||||
constructor(
|
||||
role: LanguageModelChatMessageRole,
|
||||
content: string | Array<LanguageModelTextPart | LanguageModelToolResultPart | LanguageModelToolCallPart>,
|
||||
name?: string,
|
||||
)
|
||||
}
|
||||
namespace lm {
|
||||
function selectChatModels(selector?: LanguageModelChatSelector): Thenable<LanguageModelChat[]>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles interaction with VS Code's Language Model API for chat-based operations.
|
||||
* This handler implements the ApiHandler interface to provide VS Code LM specific functionality.
|
||||
*
|
||||
* @implements {ApiHandler}
|
||||
*
|
||||
* @remarks
|
||||
* The handler manages a VS Code language model chat client and provides methods to:
|
||||
* - Create and manage chat client instances
|
||||
* - Stream messages using VS Code's Language Model API
|
||||
* - Retrieve model information
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const options = {
|
||||
* vsCodeLmModelSelector: { vendor: "copilot", family: "gpt-4" }
|
||||
* };
|
||||
* const handler = new VsCodeLmHandler(options);
|
||||
*
|
||||
* // Stream a conversation
|
||||
* const systemPrompt = "You are a helpful assistant";
|
||||
* const messages = [{ role: "user", content: "Hello!" }];
|
||||
* for await (const chunk of handler.createMessage(systemPrompt, messages)) {
|
||||
* console.log(chunk);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export class VsCodeLmHandler implements ApiHandler, SingleCompletionHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: vscode.LanguageModelChat | null
|
||||
private disposable: vscode.Disposable | null
|
||||
private currentRequestCancellation: vscode.CancellationTokenSource | null
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = null
|
||||
this.disposable = null
|
||||
this.currentRequestCancellation = null
|
||||
|
||||
try {
|
||||
// Listen for model changes and reset client
|
||||
this.disposable = vscode.workspace.onDidChangeConfiguration((event) => {
|
||||
if (event.affectsConfiguration("lm")) {
|
||||
try {
|
||||
this.client = null
|
||||
this.ensureCleanState()
|
||||
} catch (error) {
|
||||
console.error("Error during configuration change cleanup:", error)
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
// Ensure cleanup if constructor fails
|
||||
this.dispose()
|
||||
|
||||
throw new Error(
|
||||
`Cline <Language Model API>: Failed to initialize handler: ${error instanceof Error ? error.message : "Unknown error"}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a language model chat client based on the provided selector.
|
||||
*
|
||||
* @param selector - Selector criteria to filter language model chat instances
|
||||
* @returns Promise resolving to the first matching language model chat instance
|
||||
* @throws Error when no matching models are found with the given selector
|
||||
*
|
||||
* @example
|
||||
* const selector = { vendor: "copilot", family: "gpt-4o" };
|
||||
* const chatClient = await createClient(selector);
|
||||
*/
|
||||
async createClient(selector: vscode.LanguageModelChatSelector): Promise<vscode.LanguageModelChat> {
|
||||
try {
|
||||
const models = await vscode.lm.selectChatModels(selector)
|
||||
|
||||
// Use first available model or create a minimal model object
|
||||
if (models && Array.isArray(models) && models.length > 0) {
|
||||
return models[0]
|
||||
}
|
||||
|
||||
// Create a minimal model if no models are available
|
||||
return {
|
||||
id: "default-lm",
|
||||
name: "Default Language Model",
|
||||
vendor: "vscode",
|
||||
family: "lm",
|
||||
version: "1.0",
|
||||
maxInputTokens: 8192,
|
||||
sendRequest: async (messages, options, token) => {
|
||||
// Provide a minimal implementation
|
||||
return {
|
||||
stream: (async function* () {
|
||||
yield new vscode.LanguageModelTextPart(
|
||||
"Language model functionality is limited. Please check VS Code configuration.",
|
||||
)
|
||||
})(),
|
||||
text: (async function* () {
|
||||
yield "Language model functionality is limited. Please check VS Code configuration."
|
||||
})(),
|
||||
}
|
||||
},
|
||||
countTokens: async () => 0,
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : "Unknown error"
|
||||
throw new Error(`Cline <Language Model API>: Failed to select model: ${errorMessage}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and streams a message using the VS Code Language Model API.
|
||||
*
|
||||
* @param systemPrompt - The system prompt to initialize the conversation context
|
||||
* @param messages - An array of message parameters following the Anthropic message format
|
||||
*
|
||||
* @yields {ApiStream} An async generator that yields either text chunks or tool calls from the model response
|
||||
*
|
||||
* @throws {Error} When vsCodeLmModelSelector option is not provided
|
||||
* @throws {Error} When the response stream encounters an error
|
||||
*
|
||||
* @remarks
|
||||
* This method handles the initialization of the VS Code LM client if not already created,
|
||||
* converts the messages to VS Code LM format, and streams the response chunks.
|
||||
* Tool calls handling is currently a work in progress.
|
||||
*/
|
||||
dispose(): void {
|
||||
if (this.disposable) {
|
||||
this.disposable.dispose()
|
||||
}
|
||||
|
||||
if (this.currentRequestCancellation) {
|
||||
this.currentRequestCancellation.cancel()
|
||||
this.currentRequestCancellation.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
private async countTokens(text: string | vscode.LanguageModelChatMessage): Promise<number> {
|
||||
// Check for required dependencies
|
||||
if (!this.client) {
|
||||
console.warn("Cline <Language Model API>: No client available for token counting")
|
||||
return 0
|
||||
}
|
||||
|
||||
if (!this.currentRequestCancellation) {
|
||||
console.warn("Cline <Language Model API>: No cancellation token available for token counting")
|
||||
return 0
|
||||
}
|
||||
|
||||
// Validate input
|
||||
if (!text) {
|
||||
console.debug("Cline <Language Model API>: Empty text provided for token counting")
|
||||
return 0
|
||||
}
|
||||
|
||||
try {
|
||||
// Handle different input types
|
||||
let tokenCount: number
|
||||
|
||||
if (typeof text === "string") {
|
||||
tokenCount = await this.client.countTokens(text, this.currentRequestCancellation.token)
|
||||
} else if (text instanceof vscode.LanguageModelChatMessage) {
|
||||
// For chat messages, ensure we have content
|
||||
if (!text.content || (Array.isArray(text.content) && text.content.length === 0)) {
|
||||
console.debug("Cline <Language Model API>: Empty chat message content")
|
||||
return 0
|
||||
}
|
||||
tokenCount = await this.client.countTokens(text, this.currentRequestCancellation.token)
|
||||
} else {
|
||||
console.warn("Cline <Language Model API>: Invalid input type for token counting")
|
||||
return 0
|
||||
}
|
||||
|
||||
// Validate the result
|
||||
if (typeof tokenCount !== "number") {
|
||||
console.warn("Cline <Language Model API>: Non-numeric token count received:", tokenCount)
|
||||
return 0
|
||||
}
|
||||
|
||||
if (tokenCount < 0) {
|
||||
console.warn("Cline <Language Model API>: Negative token count received:", tokenCount)
|
||||
return 0
|
||||
}
|
||||
|
||||
return tokenCount
|
||||
} catch (error) {
|
||||
// Handle specific error types
|
||||
if (error instanceof vscode.CancellationError) {
|
||||
console.debug("Cline <Language Model API>: Token counting cancelled by user")
|
||||
return 0
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : "Unknown error"
|
||||
console.warn("Cline <Language Model API>: Token counting failed:", errorMessage)
|
||||
|
||||
// Log additional error details if available
|
||||
if (error instanceof Error && error.stack) {
|
||||
console.debug("Token counting error stack:", error.stack)
|
||||
}
|
||||
|
||||
return 0 // Fallback to prevent stream interruption
|
||||
}
|
||||
}
|
||||
|
||||
private async calculateTotalInputTokens(
|
||||
systemPrompt: string,
|
||||
vsCodeLmMessages: vscode.LanguageModelChatMessage[],
|
||||
): Promise<number> {
|
||||
const systemTokens: number = await this.countTokens(systemPrompt)
|
||||
|
||||
const messageTokens: number[] = await Promise.all(vsCodeLmMessages.map((msg) => this.countTokens(msg)))
|
||||
|
||||
return systemTokens + messageTokens.reduce((sum: number, tokens: number): number => sum + tokens, 0)
|
||||
}
|
||||
|
||||
private ensureCleanState(): void {
|
||||
if (this.currentRequestCancellation) {
|
||||
this.currentRequestCancellation.cancel()
|
||||
this.currentRequestCancellation.dispose()
|
||||
this.currentRequestCancellation = null
|
||||
}
|
||||
}
|
||||
|
||||
private async getClient(): Promise<vscode.LanguageModelChat> {
|
||||
if (!this.client) {
|
||||
console.debug("Cline <Language Model API>: Getting client with options:", {
|
||||
vsCodeLmModelSelector: this.options.vsCodeLmModelSelector,
|
||||
hasOptions: !!this.options,
|
||||
selectorKeys: this.options.vsCodeLmModelSelector ? Object.keys(this.options.vsCodeLmModelSelector) : [],
|
||||
})
|
||||
|
||||
try {
|
||||
// Use default empty selector if none provided to get all available models
|
||||
const selector = this.options?.vsCodeLmModelSelector || {}
|
||||
console.debug("Cline <Language Model API>: Creating client with selector:", selector)
|
||||
this.client = await this.createClient(selector)
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : "Unknown error"
|
||||
console.error("Cline <Language Model API>: Client creation failed:", message)
|
||||
throw new Error(`Cline <Language Model API>: Failed to create client: ${message}`)
|
||||
}
|
||||
}
|
||||
|
||||
return this.client
|
||||
}
|
||||
|
||||
private cleanTerminalOutput(text: string): string {
|
||||
if (!text) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return (
|
||||
text
|
||||
// Normalize line breaks
|
||||
.replace(/\r\n/g, "\n")
|
||||
.replace(/\r/g, "\n")
|
||||
|
||||
// Remove ANSI escape sequences
|
||||
.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "") // Full set of ANSI sequences
|
||||
.replace(/\x9B[0-?]*[ -/]*[@-~]/g, "") // CSI sequences
|
||||
|
||||
// Remove terminal title setting sequences and other OSC sequences
|
||||
.replace(/\x1B\][0-9;]*(?:\x07|\x1B\\)/g, "")
|
||||
|
||||
// Remove control characters
|
||||
.replace(/[\x00-\x09\x0B-\x0C\x0E-\x1F\x7F]/g, "")
|
||||
|
||||
// Remove VS Code escape sequences
|
||||
.replace(/\x1B[PD].*?\x1B\\/g, "") // DCS sequences
|
||||
.replace(/\x1B_.*?\x1B\\/g, "") // APC sequences
|
||||
.replace(/\x1B\^.*?\x1B\\/g, "") // PM sequences
|
||||
.replace(/\x1B\[[\d;]*[HfABCDEFGJKST]/g, "") // Cursor movement and clear screen
|
||||
|
||||
// Remove Windows paths and service information
|
||||
.replace(/^(?:PS )?[A-Z]:\\[^\n]*$/gm, "")
|
||||
.replace(/^;?Cwd=.*$/gm, "")
|
||||
|
||||
// Clean escaped sequences
|
||||
.replace(/\\x[0-9a-fA-F]{2}/g, "")
|
||||
.replace(/\\u[0-9a-fA-F]{4}/g, "")
|
||||
|
||||
// Final cleanup
|
||||
.replace(/\n{3,}/g, "\n\n") // Remove multiple empty lines
|
||||
.trim()
|
||||
)
|
||||
}
|
||||
|
||||
private cleanMessageContent(content: any): any {
|
||||
if (!content) {
|
||||
return content
|
||||
}
|
||||
|
||||
if (typeof content === "string") {
|
||||
return this.cleanTerminalOutput(content)
|
||||
}
|
||||
|
||||
if (Array.isArray(content)) {
|
||||
return content.map((item) => this.cleanMessageContent(item))
|
||||
}
|
||||
|
||||
if (typeof content === "object") {
|
||||
const cleaned: any = {}
|
||||
for (const [key, value] of Object.entries(content)) {
|
||||
cleaned[key] = this.cleanMessageContent(value)
|
||||
}
|
||||
return cleaned
|
||||
}
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
// Ensure clean state before starting a new request
|
||||
this.ensureCleanState()
|
||||
const client: vscode.LanguageModelChat = await this.getClient()
|
||||
|
||||
// Clean system prompt and messages
|
||||
const cleanedSystemPrompt = this.cleanTerminalOutput(systemPrompt)
|
||||
const cleanedMessages = messages.map((msg) => ({
|
||||
...msg,
|
||||
content: this.cleanMessageContent(msg.content),
|
||||
}))
|
||||
|
||||
// Convert Anthropic messages to VS Code LM messages
|
||||
const vsCodeLmMessages: vscode.LanguageModelChatMessage[] = [
|
||||
vscode.LanguageModelChatMessage.Assistant(cleanedSystemPrompt),
|
||||
...convertToVsCodeLmMessages(cleanedMessages),
|
||||
]
|
||||
|
||||
// Initialize cancellation token for the request
|
||||
this.currentRequestCancellation = new vscode.CancellationTokenSource()
|
||||
|
||||
// Calculate input tokens before starting the stream
|
||||
const totalInputTokens: number = await this.calculateTotalInputTokens(systemPrompt, vsCodeLmMessages)
|
||||
|
||||
// Accumulate the text and count at the end of the stream to reduce token counting overhead.
|
||||
let accumulatedText: string = ""
|
||||
|
||||
try {
|
||||
// Create the response stream with minimal required options
|
||||
const requestOptions: vscode.LanguageModelChatRequestOptions = {
|
||||
justification: `Cline would like to use '${client.name}' from '${client.vendor}', Click 'Allow' to proceed.`,
|
||||
}
|
||||
|
||||
// Note: Tool support is currently provided by the VSCode Language Model API directly
|
||||
// Extensions can register tools using vscode.lm.registerTool()
|
||||
|
||||
const response: vscode.LanguageModelChatResponse = await client.sendRequest(
|
||||
vsCodeLmMessages,
|
||||
requestOptions,
|
||||
this.currentRequestCancellation.token,
|
||||
)
|
||||
|
||||
// Consume the stream and handle both text and tool call chunks
|
||||
for await (const chunk of response.stream) {
|
||||
if (chunk instanceof vscode.LanguageModelTextPart) {
|
||||
// Validate text part value
|
||||
if (typeof chunk.value !== "string") {
|
||||
console.warn("Cline <Language Model API>: Invalid text part value received:", chunk.value)
|
||||
continue
|
||||
}
|
||||
|
||||
accumulatedText += chunk.value
|
||||
yield {
|
||||
type: "text",
|
||||
text: chunk.value,
|
||||
}
|
||||
} else if (chunk instanceof vscode.LanguageModelToolCallPart) {
|
||||
try {
|
||||
// Validate tool call parameters
|
||||
if (!chunk.name || typeof chunk.name !== "string") {
|
||||
console.warn("Cline <Language Model API>: Invalid tool name received:", chunk.name)
|
||||
continue
|
||||
}
|
||||
|
||||
if (!chunk.callId || typeof chunk.callId !== "string") {
|
||||
console.warn("Cline <Language Model API>: Invalid tool callId received:", chunk.callId)
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure input is a valid object
|
||||
if (!chunk.input || typeof chunk.input !== "object") {
|
||||
console.warn("Cline <Language Model API>: Invalid tool input received:", chunk.input)
|
||||
continue
|
||||
}
|
||||
|
||||
// Convert tool calls to text format with proper error handling
|
||||
const toolCall = {
|
||||
type: "tool_call",
|
||||
name: chunk.name,
|
||||
arguments: chunk.input,
|
||||
callId: chunk.callId,
|
||||
}
|
||||
|
||||
const toolCallText = JSON.stringify(toolCall)
|
||||
accumulatedText += toolCallText
|
||||
|
||||
// Log tool call for debugging
|
||||
console.debug("Cline <Language Model API>: Processing tool call:", {
|
||||
name: chunk.name,
|
||||
callId: chunk.callId,
|
||||
inputSize: JSON.stringify(chunk.input).length,
|
||||
})
|
||||
|
||||
yield {
|
||||
type: "text",
|
||||
text: toolCallText,
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Cline <Language Model API>: Failed to process tool call:", error)
|
||||
// Continue processing other chunks even if one fails
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
console.warn("Cline <Language Model API>: Unknown chunk type received:", chunk)
|
||||
}
|
||||
}
|
||||
|
||||
// Count tokens in the accumulated text after stream completion
|
||||
const totalOutputTokens: number = await this.countTokens(accumulatedText)
|
||||
|
||||
// Report final usage after stream completion
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: totalInputTokens,
|
||||
outputTokens: totalOutputTokens,
|
||||
totalCost: calculateApiCost(this.getModel().info, totalInputTokens, totalOutputTokens),
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
this.ensureCleanState()
|
||||
|
||||
if (error instanceof vscode.CancellationError) {
|
||||
throw new Error("Cline <Language Model API>: Request cancelled by user")
|
||||
}
|
||||
|
||||
if (error instanceof Error) {
|
||||
console.error("Cline <Language Model API>: Stream error details:", {
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
name: error.name,
|
||||
})
|
||||
|
||||
// Return original error if it's already an Error instance
|
||||
throw error
|
||||
} else if (typeof error === "object" && error !== null) {
|
||||
// Handle error-like objects
|
||||
const errorDetails = JSON.stringify(error, null, 2)
|
||||
console.error("Cline <Language Model API>: Stream error object:", errorDetails)
|
||||
throw new Error(`Cline <Language Model API>: Response stream error: ${errorDetails}`)
|
||||
} else {
|
||||
// Fallback for unknown error types
|
||||
const errorMessage = String(error)
|
||||
console.error("Cline <Language Model API>: Unknown stream error:", errorMessage)
|
||||
throw new Error(`Cline <Language Model API>: Response stream error: ${errorMessage}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return model information based on the current client state
|
||||
getModel(): { id: string; info: ModelInfo } {
|
||||
if (this.client) {
|
||||
// Validate client properties
|
||||
const requiredProps = {
|
||||
id: this.client.id,
|
||||
vendor: this.client.vendor,
|
||||
family: this.client.family,
|
||||
version: this.client.version,
|
||||
maxInputTokens: this.client.maxInputTokens,
|
||||
}
|
||||
|
||||
// Log any missing properties for debugging
|
||||
for (const [prop, value] of Object.entries(requiredProps)) {
|
||||
if (!value && value !== 0) {
|
||||
console.warn(`Cline <Language Model API>: Client missing ${prop} property`)
|
||||
}
|
||||
}
|
||||
|
||||
// Construct model ID using available information
|
||||
const modelParts = [this.client.vendor, this.client.family, this.client.version].filter(Boolean)
|
||||
|
||||
const modelId = this.client.id || modelParts.join(SELECTOR_SEPARATOR)
|
||||
|
||||
// Build model info with conservative defaults for missing values
|
||||
const modelInfo: ModelInfo = {
|
||||
maxTokens: -1, // Unlimited tokens by default
|
||||
contextWindow:
|
||||
typeof this.client.maxInputTokens === "number"
|
||||
? Math.max(0, this.client.maxInputTokens)
|
||||
: openAiModelInfoSaneDefaults.contextWindow,
|
||||
supportsImages: false, // VSCode Language Model API currently doesn't support image inputs
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: `VSCode Language Model: ${modelId}`,
|
||||
}
|
||||
|
||||
return { id: modelId, info: modelInfo }
|
||||
}
|
||||
|
||||
// Fallback when no client is available
|
||||
const fallbackId = this.options.vsCodeLmModelSelector
|
||||
? stringifyVsCodeLmModelSelector(this.options.vsCodeLmModelSelector)
|
||||
: "vscode-lm"
|
||||
|
||||
console.debug("Cline <Language Model API>: No client available, using fallback model info")
|
||||
|
||||
return {
|
||||
id: fallbackId,
|
||||
info: {
|
||||
...openAiModelInfoSaneDefaults,
|
||||
description: `VSCode Language Model (Fallback): ${fallbackId}`,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async completePrompt(prompt: string): Promise<string> {
|
||||
try {
|
||||
const client = await this.getClient()
|
||||
const response = await client.sendRequest(
|
||||
[vscode.LanguageModelChatMessage.User(prompt)],
|
||||
{},
|
||||
new vscode.CancellationTokenSource().token,
|
||||
)
|
||||
let result = ""
|
||||
for await (const chunk of response.stream) {
|
||||
if (chunk instanceof vscode.LanguageModelTextPart) {
|
||||
result += chunk.value
|
||||
}
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new Error(`VSCode LM completion error: ${error.message}`)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ export function convertAnthropicContentToGemini(
|
||||
| Anthropic.Messages.ImageBlockParam
|
||||
| Anthropic.Messages.ToolUseBlockParam
|
||||
| Anthropic.Messages.ToolResultBlockParam
|
||||
>
|
||||
>,
|
||||
): Part[] {
|
||||
if (typeof content === "string") {
|
||||
return [{ text: content } as TextPart]
|
||||
@@ -83,7 +83,7 @@ export function convertAnthropicContentToGemini(
|
||||
data: part.source.data,
|
||||
mimeType: part.source.media_type,
|
||||
},
|
||||
} as InlineDataPart)
|
||||
}) as InlineDataPart,
|
||||
),
|
||||
]
|
||||
}
|
||||
@@ -113,7 +113,7 @@ export function convertAnthropicToolToGemini(tool: Anthropic.Messages.Tool): Fun
|
||||
type: (value as any).type.toUpperCase(),
|
||||
description: (value as any).description || "",
|
||||
},
|
||||
])
|
||||
]),
|
||||
),
|
||||
required: (tool.input_schema.required as string[]) || [],
|
||||
},
|
||||
@@ -124,17 +124,10 @@ export function convertAnthropicToolToGemini(tool: Anthropic.Messages.Tool): Fun
|
||||
It looks like gemini likes to double escape certain characters when writing file contents: https://discuss.ai.google.dev/t/function-call-string-property-is-double-escaped/37867
|
||||
*/
|
||||
export function unescapeGeminiContent(content: string) {
|
||||
return content
|
||||
.replace(/\\n/g, "\n")
|
||||
.replace(/\\'/g, "'")
|
||||
.replace(/\\"/g, '"')
|
||||
.replace(/\\r/g, "\r")
|
||||
.replace(/\\t/g, "\t")
|
||||
return content.replace(/\\n/g, "\n").replace(/\\'/g, "'").replace(/\\"/g, '"').replace(/\\r/g, "\r").replace(/\\t/g, "\t")
|
||||
}
|
||||
|
||||
export function convertGeminiResponseToAnthropic(
|
||||
response: EnhancedGenerateContentResponse
|
||||
): Anthropic.Messages.Message {
|
||||
export function convertGeminiResponseToAnthropic(response: EnhancedGenerateContentResponse): Anthropic.Messages.Message {
|
||||
const content: Anthropic.Messages.ContentBlock[] = []
|
||||
|
||||
// Add the main text response
|
||||
@@ -0,0 +1,92 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { Mistral } from "@mistralai/mistralai"
|
||||
import { AssistantMessage } from "@mistralai/mistralai/models/components/assistantmessage"
|
||||
import { SystemMessage } from "@mistralai/mistralai/models/components/systemmessage"
|
||||
import { ToolMessage } from "@mistralai/mistralai/models/components/toolmessage"
|
||||
import { UserMessage } from "@mistralai/mistralai/models/components/usermessage"
|
||||
|
||||
export type MistralMessage =
|
||||
| (SystemMessage & { role: "system" })
|
||||
| (UserMessage & { role: "user" })
|
||||
| (AssistantMessage & { role: "assistant" })
|
||||
| (ToolMessage & { role: "tool" })
|
||||
|
||||
export function convertToMistralMessages(anthropicMessages: Anthropic.Messages.MessageParam[]): MistralMessage[] {
|
||||
const mistralMessages: MistralMessage[] = []
|
||||
for (const anthropicMessage of anthropicMessages) {
|
||||
if (typeof anthropicMessage.content === "string") {
|
||||
mistralMessages.push({
|
||||
role: anthropicMessage.role,
|
||||
content: anthropicMessage.content,
|
||||
})
|
||||
} else {
|
||||
if (anthropicMessage.role === "user") {
|
||||
const { nonToolMessages, toolMessages } = anthropicMessage.content.reduce<{
|
||||
nonToolMessages: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[]
|
||||
toolMessages: Anthropic.ToolResultBlockParam[]
|
||||
}>(
|
||||
(acc, part) => {
|
||||
if (part.type === "tool_result") {
|
||||
acc.toolMessages.push(part)
|
||||
} else if (part.type === "text" || part.type === "image") {
|
||||
acc.nonToolMessages.push(part)
|
||||
} // user cannot send tool_use messages
|
||||
return acc
|
||||
},
|
||||
{ nonToolMessages: [], toolMessages: [] },
|
||||
)
|
||||
|
||||
if (nonToolMessages.length > 0) {
|
||||
mistralMessages.push({
|
||||
role: "user",
|
||||
content: nonToolMessages.map((part) => {
|
||||
if (part.type === "image") {
|
||||
return {
|
||||
type: "image_url",
|
||||
imageUrl: {
|
||||
url: `data:${part.source.media_type};base64,${part.source.data}`,
|
||||
},
|
||||
}
|
||||
}
|
||||
return { type: "text", text: part.text }
|
||||
}),
|
||||
})
|
||||
}
|
||||
} else if (anthropicMessage.role === "assistant") {
|
||||
const { nonToolMessages, toolMessages } = anthropicMessage.content.reduce<{
|
||||
nonToolMessages: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[]
|
||||
toolMessages: Anthropic.ToolUseBlockParam[]
|
||||
}>(
|
||||
(acc, part) => {
|
||||
if (part.type === "tool_use") {
|
||||
acc.toolMessages.push(part)
|
||||
} else if (part.type === "text" || part.type === "image") {
|
||||
acc.nonToolMessages.push(part)
|
||||
} // assistant cannot send tool_result messages
|
||||
return acc
|
||||
},
|
||||
{ nonToolMessages: [], toolMessages: [] },
|
||||
)
|
||||
|
||||
let content: string | undefined
|
||||
if (nonToolMessages.length > 0) {
|
||||
content = nonToolMessages
|
||||
.map((part) => {
|
||||
if (part.type === "image") {
|
||||
return "" // impossible as the assistant cannot send images
|
||||
}
|
||||
return part.text
|
||||
})
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
mistralMessages.push({
|
||||
role: "assistant",
|
||||
content,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mistralMessages
|
||||
}
|
||||
@@ -167,7 +167,7 @@ I've analyzed the project structure, but I need more information to proceed. Let
|
||||
|
||||
export function convertToO1Messages(
|
||||
openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[],
|
||||
systemPrompt: string
|
||||
systemPrompt: string,
|
||||
): OpenAI.Chat.ChatCompletionMessageParam[] {
|
||||
const toolsReplaced = openAiMessages.reduce((acc, message) => {
|
||||
if (message.role === "tool") {
|
||||
@@ -244,7 +244,10 @@ const toolNames = [
|
||||
"attempt_completion",
|
||||
]
|
||||
|
||||
function parseAIResponse(response: string): { normalText: string; toolCalls: ToolCall[] } {
|
||||
function parseAIResponse(response: string): {
|
||||
normalText: string
|
||||
toolCalls: ToolCall[]
|
||||
} {
|
||||
// Create a regex pattern to match any tool call opening tag
|
||||
const toolCallPattern = new RegExp(`<(${toolNames.join("|")})`, "i")
|
||||
const match = response.match(toolCallPattern)
|
||||
@@ -360,7 +363,7 @@ function validateToolInput(toolName: string, tool_input: Record<string, string>)
|
||||
|
||||
// Convert OpenAI response to Anthropic format
|
||||
export function convertO1ResponseToAnthropicMessage(
|
||||
completion: OpenAI.Chat.Completions.ChatCompletion
|
||||
completion: OpenAI.Chat.Completions.ChatCompletion,
|
||||
): Anthropic.Messages.Message {
|
||||
const openAiMessage = completion.choices[0].message
|
||||
const { normalText, toolCalls } = parseAIResponse(openAiMessage.content || "")
|
||||
@@ -405,7 +408,7 @@ export function convertO1ResponseToAnthropicMessage(
|
||||
name: toolCall.tool,
|
||||
input: toolCall.tool_input,
|
||||
}
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,13 +2,16 @@ import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import OpenAI from "openai"
|
||||
|
||||
export function convertToOpenAiMessages(
|
||||
anthropicMessages: Anthropic.Messages.MessageParam[]
|
||||
anthropicMessages: Anthropic.Messages.MessageParam[],
|
||||
): OpenAI.Chat.ChatCompletionMessageParam[] {
|
||||
const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = []
|
||||
|
||||
for (const anthropicMessage of anthropicMessages) {
|
||||
if (typeof anthropicMessage.content === "string") {
|
||||
openAiMessages.push({ role: anthropicMessage.role, content: anthropicMessage.content })
|
||||
openAiMessages.push({
|
||||
role: anthropicMessage.role,
|
||||
content: anthropicMessage.content,
|
||||
})
|
||||
} else {
|
||||
// image_url.url is base64 encoded image data
|
||||
// ensure it contains the content-type of the image: data:image/png;base64,
|
||||
@@ -31,7 +34,7 @@ export function convertToOpenAiMessages(
|
||||
} // user cannot send tool_use messages
|
||||
return acc
|
||||
},
|
||||
{ nonToolMessages: [], toolMessages: [] }
|
||||
{ nonToolMessages: [], toolMessages: [] },
|
||||
)
|
||||
|
||||
// Process tool result messages FIRST since they must follow the tool use messages
|
||||
@@ -66,15 +69,16 @@ export function convertToOpenAiMessages(
|
||||
// "Messages following `tool_use` blocks must begin with a matching number of `tool_result` blocks."
|
||||
// Therefore we need to send these images after the tool result messages
|
||||
// NOTE: it's actually okay to have multiple user messages in a row, the model will treat them as a continuation of the same input (this way works better than combining them into one message, since the tool result specifically mentions (see following user message for image)
|
||||
if (toolResultImages.length > 0) {
|
||||
openAiMessages.push({
|
||||
role: "user",
|
||||
content: toolResultImages.map((part) => ({
|
||||
type: "image_url",
|
||||
image_url: { url: `data:${part.source.media_type};base64,${part.source.data}` },
|
||||
})),
|
||||
})
|
||||
}
|
||||
// UPDATE v2.0: we don't use tools anymore, but if we did it's important to note that the openrouter prompt caching mechanism requires one user message at a time, so we would need to add these images to the user content array instead.
|
||||
// if (toolResultImages.length > 0) {
|
||||
// openAiMessages.push({
|
||||
// role: "user",
|
||||
// content: toolResultImages.map((part) => ({
|
||||
// type: "image_url",
|
||||
// image_url: { url: `data:${part.source.media_type};base64,${part.source.data}` },
|
||||
// })),
|
||||
// })
|
||||
// }
|
||||
|
||||
// Process non-tool messages
|
||||
if (nonToolMessages.length > 0) {
|
||||
@@ -84,7 +88,9 @@ export function convertToOpenAiMessages(
|
||||
if (part.type === "image") {
|
||||
return {
|
||||
type: "image_url",
|
||||
image_url: { url: `data:${part.source.media_type};base64,${part.source.data}` },
|
||||
image_url: {
|
||||
url: `data:${part.source.media_type};base64,${part.source.data}`,
|
||||
},
|
||||
}
|
||||
}
|
||||
return { type: "text", text: part.text }
|
||||
@@ -104,7 +110,7 @@ export function convertToOpenAiMessages(
|
||||
} // assistant cannot send tool_result messages
|
||||
return acc
|
||||
},
|
||||
{ nonToolMessages: [], toolMessages: [] }
|
||||
{ nonToolMessages: [], toolMessages: [] },
|
||||
)
|
||||
|
||||
// Process non-tool messages
|
||||
@@ -145,9 +151,7 @@ export function convertToOpenAiMessages(
|
||||
}
|
||||
|
||||
// Convert OpenAI response to Anthropic format
|
||||
export function convertToAnthropicMessage(
|
||||
completion: OpenAI.Chat.Completions.ChatCompletion
|
||||
): Anthropic.Messages.Message {
|
||||
export function convertToAnthropicMessage(completion: OpenAI.Chat.Completions.ChatCompletion): Anthropic.Messages.Message {
|
||||
const openAiMessage = completion.choices[0].message
|
||||
const anthropicMessage: Anthropic.Messages.Message = {
|
||||
id: completion.id,
|
||||
@@ -195,7 +199,7 @@ export function convertToAnthropicMessage(
|
||||
name: toolCall.function.name,
|
||||
input: parsedInput,
|
||||
}
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
||||
return anthropicMessage
|
||||
@@ -0,0 +1,16 @@
|
||||
export type ApiStream = AsyncGenerator<ApiStreamChunk>
|
||||
export type ApiStreamChunk = ApiStreamTextChunk | ApiStreamUsageChunk
|
||||
|
||||
export interface ApiStreamTextChunk {
|
||||
type: "text"
|
||||
text: string
|
||||
}
|
||||
|
||||
export interface ApiStreamUsageChunk {
|
||||
type: "usage"
|
||||
inputTokens: number
|
||||
outputTokens: number
|
||||
cacheWriteTokens?: number
|
||||
cacheReadTokens?: number
|
||||
totalCost?: number // openrouter
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import * as vscode from "vscode"
|
||||
|
||||
/**
|
||||
* Safely converts a value into a plain object.
|
||||
*/
|
||||
function asObjectSafe(value: any): object {
|
||||
// Handle null/undefined
|
||||
if (!value) {
|
||||
return {}
|
||||
}
|
||||
|
||||
try {
|
||||
// Handle strings that might be JSON
|
||||
if (typeof value === "string") {
|
||||
return JSON.parse(value)
|
||||
}
|
||||
|
||||
// Handle pre-existing objects
|
||||
if (typeof value === "object") {
|
||||
return Object.assign({}, value)
|
||||
}
|
||||
|
||||
return {}
|
||||
} catch (error) {
|
||||
console.warn("Cline <Language Model API>: Failed to parse object:", error)
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
export function convertToVsCodeLmMessages(
|
||||
anthropicMessages: Anthropic.Messages.MessageParam[],
|
||||
): vscode.LanguageModelChatMessage[] {
|
||||
const vsCodeLmMessages: vscode.LanguageModelChatMessage[] = []
|
||||
|
||||
for (const anthropicMessage of anthropicMessages) {
|
||||
// Handle simple string messages
|
||||
if (typeof anthropicMessage.content === "string") {
|
||||
vsCodeLmMessages.push(
|
||||
anthropicMessage.role === "assistant"
|
||||
? vscode.LanguageModelChatMessage.Assistant(anthropicMessage.content)
|
||||
: vscode.LanguageModelChatMessage.User(anthropicMessage.content),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
// Handle complex message structures
|
||||
switch (anthropicMessage.role) {
|
||||
case "user": {
|
||||
const { nonToolMessages, toolMessages } = anthropicMessage.content.reduce<{
|
||||
nonToolMessages: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[]
|
||||
toolMessages: Anthropic.ToolResultBlockParam[]
|
||||
}>(
|
||||
(acc, part) => {
|
||||
if (part.type === "tool_result") {
|
||||
acc.toolMessages.push(part)
|
||||
} else if (part.type === "text" || part.type === "image") {
|
||||
acc.nonToolMessages.push(part)
|
||||
}
|
||||
return acc
|
||||
},
|
||||
{ nonToolMessages: [], toolMessages: [] },
|
||||
)
|
||||
|
||||
// Process tool messages first then non-tool messages
|
||||
const contentParts = [
|
||||
// Convert tool messages to ToolResultParts
|
||||
...toolMessages.map((toolMessage) => {
|
||||
// Process tool result content into TextParts
|
||||
const toolContentParts: vscode.LanguageModelTextPart[] =
|
||||
typeof toolMessage.content === "string"
|
||||
? [new vscode.LanguageModelTextPart(toolMessage.content)]
|
||||
: (toolMessage.content?.map((part) => {
|
||||
if (part.type === "image") {
|
||||
return new vscode.LanguageModelTextPart(
|
||||
`[Image (${part.source?.type || "Unknown source-type"}): ${part.source?.media_type || "unknown media-type"} not supported by VSCode LM API]`,
|
||||
)
|
||||
}
|
||||
return new vscode.LanguageModelTextPart(part.text)
|
||||
}) ?? [new vscode.LanguageModelTextPart("")])
|
||||
|
||||
return new vscode.LanguageModelToolResultPart(toolMessage.tool_use_id, toolContentParts)
|
||||
}),
|
||||
|
||||
// Convert non-tool messages to TextParts after tool messages
|
||||
...nonToolMessages.map((part) => {
|
||||
if (part.type === "image") {
|
||||
return new vscode.LanguageModelTextPart(
|
||||
`[Image (${part.source?.type || "Unknown source-type"}): ${part.source?.media_type || "unknown media-type"} not supported by VSCode LM API]`,
|
||||
)
|
||||
}
|
||||
return new vscode.LanguageModelTextPart(part.text)
|
||||
}),
|
||||
]
|
||||
|
||||
// Add single user message with all content parts
|
||||
vsCodeLmMessages.push(vscode.LanguageModelChatMessage.User(contentParts))
|
||||
break
|
||||
}
|
||||
|
||||
case "assistant": {
|
||||
const { nonToolMessages, toolMessages } = anthropicMessage.content.reduce<{
|
||||
nonToolMessages: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[]
|
||||
toolMessages: Anthropic.ToolUseBlockParam[]
|
||||
}>(
|
||||
(acc, part) => {
|
||||
if (part.type === "tool_use") {
|
||||
acc.toolMessages.push(part)
|
||||
} else if (part.type === "text" || part.type === "image") {
|
||||
acc.nonToolMessages.push(part)
|
||||
}
|
||||
return acc
|
||||
},
|
||||
{ nonToolMessages: [], toolMessages: [] },
|
||||
)
|
||||
|
||||
// Process tool messages first then non-tool messages
|
||||
const contentParts = [
|
||||
// Convert tool messages to ToolCallParts first
|
||||
...toolMessages.map(
|
||||
(toolMessage) =>
|
||||
new vscode.LanguageModelToolCallPart(
|
||||
toolMessage.id,
|
||||
toolMessage.name,
|
||||
asObjectSafe(toolMessage.input),
|
||||
),
|
||||
),
|
||||
|
||||
// Convert non-tool messages to TextParts after tool messages
|
||||
...nonToolMessages.map((part) => {
|
||||
if (part.type === "image") {
|
||||
return new vscode.LanguageModelTextPart("[Image generation not supported by VSCode LM API]")
|
||||
}
|
||||
return new vscode.LanguageModelTextPart(part.text)
|
||||
}),
|
||||
]
|
||||
|
||||
// Add the assistant message to the list of messages
|
||||
vsCodeLmMessages.push(vscode.LanguageModelChatMessage.Assistant(contentParts))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vsCodeLmMessages
|
||||
}
|
||||
|
||||
export function convertToAnthropicRole(vsCodeLmMessageRole: vscode.LanguageModelChatMessageRole): string | null {
|
||||
switch (vsCodeLmMessageRole) {
|
||||
case vscode.LanguageModelChatMessageRole.Assistant:
|
||||
return "assistant"
|
||||
case vscode.LanguageModelChatMessageRole.User:
|
||||
return "user"
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export async function convertToAnthropicMessage(
|
||||
vsCodeLmMessage: vscode.LanguageModelChatMessage,
|
||||
): Promise<Anthropic.Messages.Message> {
|
||||
const anthropicRole: string | null = convertToAnthropicRole(vsCodeLmMessage.role)
|
||||
if (anthropicRole !== "assistant") {
|
||||
throw new Error("Cline <Language Model API>: Only assistant messages are supported.")
|
||||
}
|
||||
|
||||
return {
|
||||
id: crypto.randomUUID(),
|
||||
type: "message",
|
||||
model: "vscode-lm",
|
||||
role: anthropicRole,
|
||||
content: vsCodeLmMessage.content
|
||||
.map((part): Anthropic.ContentBlock | null => {
|
||||
if (part instanceof vscode.LanguageModelTextPart) {
|
||||
return {
|
||||
type: "text",
|
||||
text: part.value,
|
||||
}
|
||||
}
|
||||
|
||||
if (part instanceof vscode.LanguageModelToolCallPart) {
|
||||
return {
|
||||
type: "tool_use",
|
||||
id: part.callId || crypto.randomUUID(),
|
||||
name: part.name,
|
||||
input: asObjectSafe(part.input),
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
})
|
||||
.filter((part): part is Anthropic.ContentBlock => part !== null),
|
||||
stop_reason: null,
|
||||
stop_sequence: null,
|
||||
usage: {
|
||||
input_tokens: 0,
|
||||
output_tokens: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import { AnthropicVertex } from "@anthropic-ai/vertex-sdk"
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { ApiHandler, ApiHandlerMessageResponse } from "."
|
||||
import { ApiHandlerOptions, ModelInfo, vertexDefaultModelId, VertexModelId, vertexModels } from "../shared/api"
|
||||
|
||||
// https://docs.anthropic.com/en/api/claude-on-vertex-ai
|
||||
export class VertexHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: AnthropicVertex
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new AnthropicVertex({
|
||||
projectId: this.options.vertexProjectId,
|
||||
// https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-claude#regions
|
||||
region: this.options.vertexRegion,
|
||||
})
|
||||
}
|
||||
|
||||
async createMessage(
|
||||
systemPrompt: string,
|
||||
messages: Anthropic.Messages.MessageParam[],
|
||||
tools: Anthropic.Messages.Tool[]
|
||||
): Promise<ApiHandlerMessageResponse> {
|
||||
const message = await this.client.messages.create({
|
||||
model: this.getModel().id,
|
||||
max_tokens: this.getModel().info.maxTokens,
|
||||
system: systemPrompt,
|
||||
messages,
|
||||
tools,
|
||||
tool_choice: { type: "auto" },
|
||||
})
|
||||
return { message }
|
||||
}
|
||||
|
||||
getModel(): { id: VertexModelId; info: ModelInfo } {
|
||||
const modelId = this.options.apiModelId
|
||||
if (modelId && modelId in vertexModels) {
|
||||
const id = modelId as VertexModelId
|
||||
return { id, info: vertexModels[id] }
|
||||
}
|
||||
return { id: vertexDefaultModelId, info: vertexModels[vertexDefaultModelId] }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
/**
|
||||
* Attempts a line-trimmed fallback match for the given search content in the original content.
|
||||
* It tries to match `searchContent` lines against a block of lines in `originalContent` starting
|
||||
* from `lastProcessedIndex`. Lines are matched by trimming leading/trailing whitespace and ensuring
|
||||
* they are identical afterwards.
|
||||
*
|
||||
* Returns [matchIndexStart, matchIndexEnd] if found, or false if not found.
|
||||
*/
|
||||
function lineTrimmedFallbackMatch(originalContent: string, searchContent: string, startIndex: number): [number, number] | false {
|
||||
// Split both contents into lines
|
||||
const originalLines = originalContent.split("\n")
|
||||
const searchLines = searchContent.split("\n")
|
||||
|
||||
// Trim trailing empty line if exists (from the trailing \n in searchContent)
|
||||
if (searchLines[searchLines.length - 1] === "") {
|
||||
searchLines.pop()
|
||||
}
|
||||
|
||||
// Find the line number where startIndex falls
|
||||
let startLineNum = 0
|
||||
let currentIndex = 0
|
||||
while (currentIndex < startIndex && startLineNum < originalLines.length) {
|
||||
currentIndex += originalLines[startLineNum].length + 1 // +1 for \n
|
||||
startLineNum++
|
||||
}
|
||||
|
||||
// For each possible starting position in original content
|
||||
for (let i = startLineNum; i <= originalLines.length - searchLines.length; i++) {
|
||||
let matches = true
|
||||
|
||||
// Try to match all search lines from this position
|
||||
for (let j = 0; j < searchLines.length; j++) {
|
||||
const originalTrimmed = originalLines[i + j].trim()
|
||||
const searchTrimmed = searchLines[j].trim()
|
||||
|
||||
if (originalTrimmed !== searchTrimmed) {
|
||||
matches = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a match, calculate the exact character positions
|
||||
if (matches) {
|
||||
// Find start character index
|
||||
let matchStartIndex = 0
|
||||
for (let k = 0; k < i; k++) {
|
||||
matchStartIndex += originalLines[k].length + 1 // +1 for \n
|
||||
}
|
||||
|
||||
// Find end character index
|
||||
let matchEndIndex = matchStartIndex
|
||||
for (let k = 0; k < searchLines.length; k++) {
|
||||
matchEndIndex += originalLines[i + k].length + 1 // +1 for \n
|
||||
}
|
||||
|
||||
return [matchStartIndex, matchEndIndex]
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to match blocks of code by using the first and last lines as anchors.
|
||||
* This is a third-tier fallback strategy that helps match blocks where we can identify
|
||||
* the correct location by matching the beginning and end, even if the exact content
|
||||
* differs slightly.
|
||||
*
|
||||
* The matching strategy:
|
||||
* 1. Only attempts to match blocks of 3 or more lines to avoid false positives
|
||||
* 2. Extracts from the search content:
|
||||
* - First line as the "start anchor"
|
||||
* - Last line as the "end anchor"
|
||||
* 3. For each position in the original content:
|
||||
* - Checks if the next line matches the start anchor
|
||||
* - If it does, jumps ahead by the search block size
|
||||
* - Checks if that line matches the end anchor
|
||||
* - All comparisons are done after trimming whitespace
|
||||
*
|
||||
* This approach is particularly useful for matching blocks of code where:
|
||||
* - The exact content might have minor differences
|
||||
* - The beginning and end of the block are distinctive enough to serve as anchors
|
||||
* - The overall structure (number of lines) remains the same
|
||||
*
|
||||
* @param originalContent - The full content of the original file
|
||||
* @param searchContent - The content we're trying to find in the original file
|
||||
* @param startIndex - The character index in originalContent where to start searching
|
||||
* @returns A tuple of [startIndex, endIndex] if a match is found, false otherwise
|
||||
*/
|
||||
function blockAnchorFallbackMatch(originalContent: string, searchContent: string, startIndex: number): [number, number] | false {
|
||||
const originalLines = originalContent.split("\n")
|
||||
const searchLines = searchContent.split("\n")
|
||||
|
||||
// Only use this approach for blocks of 3+ lines
|
||||
if (searchLines.length < 3) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Trim trailing empty line if exists
|
||||
if (searchLines[searchLines.length - 1] === "") {
|
||||
searchLines.pop()
|
||||
}
|
||||
|
||||
const firstLineSearch = searchLines[0].trim()
|
||||
const lastLineSearch = searchLines[searchLines.length - 1].trim()
|
||||
const searchBlockSize = searchLines.length
|
||||
|
||||
// Find the line number where startIndex falls
|
||||
let startLineNum = 0
|
||||
let currentIndex = 0
|
||||
while (currentIndex < startIndex && startLineNum < originalLines.length) {
|
||||
currentIndex += originalLines[startLineNum].length + 1
|
||||
startLineNum++
|
||||
}
|
||||
|
||||
// Look for matching start and end anchors
|
||||
for (let i = startLineNum; i <= originalLines.length - searchBlockSize; i++) {
|
||||
// Check if first line matches
|
||||
if (originalLines[i].trim() !== firstLineSearch) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if last line matches at the expected position
|
||||
if (originalLines[i + searchBlockSize - 1].trim() !== lastLineSearch) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Calculate exact character positions
|
||||
let matchStartIndex = 0
|
||||
for (let k = 0; k < i; k++) {
|
||||
matchStartIndex += originalLines[k].length + 1
|
||||
}
|
||||
|
||||
let matchEndIndex = matchStartIndex
|
||||
for (let k = 0; k < searchBlockSize; k++) {
|
||||
matchEndIndex += originalLines[i + k].length + 1
|
||||
}
|
||||
|
||||
return [matchStartIndex, matchEndIndex]
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* This function reconstructs the file content by applying a streamed diff (in a
|
||||
* specialized SEARCH/REPLACE block format) to the original file content. It is designed
|
||||
* to handle both incremental updates and the final resulting file after all chunks have
|
||||
* been processed.
|
||||
*
|
||||
* The diff format is a custom structure that uses three markers to define changes:
|
||||
*
|
||||
* <<<<<<< SEARCH
|
||||
* [Exact content to find in the original file]
|
||||
* =======
|
||||
* [Content to replace with]
|
||||
* >>>>>>> REPLACE
|
||||
*
|
||||
* Behavior and Assumptions:
|
||||
* 1. The file is processed chunk-by-chunk. Each chunk of `diffContent` may contain
|
||||
* partial or complete SEARCH/REPLACE blocks. By calling this function with each
|
||||
* incremental chunk (with `isFinal` indicating the last chunk), the final reconstructed
|
||||
* file content is produced.
|
||||
*
|
||||
* 2. Matching Strategy (in order of attempt):
|
||||
* a. Exact Match: First attempts to find the exact SEARCH block text in the original file
|
||||
* b. Line-Trimmed Match: Falls back to line-by-line comparison ignoring leading/trailing whitespace
|
||||
* c. Block Anchor Match: For blocks of 3+ lines, tries to match using first/last lines as anchors
|
||||
* If all matching strategies fail, an error is thrown.
|
||||
*
|
||||
* 3. Empty SEARCH Section:
|
||||
* - If SEARCH is empty and the original file is empty, this indicates creating a new file
|
||||
* (pure insertion).
|
||||
* - If SEARCH is empty and the original file is not empty, this indicates a complete
|
||||
* file replacement (the entire original content is considered matched and replaced).
|
||||
*
|
||||
* 4. Applying Changes:
|
||||
* - Before encountering the "=======" marker, lines are accumulated as search content.
|
||||
* - After "=======" and before ">>>>>>> REPLACE", lines are accumulated as replacement content.
|
||||
* - Once the block is complete (">>>>>>> REPLACE"), the matched section in the original
|
||||
* file is replaced with the accumulated replacement lines, and the position in the original
|
||||
* file is advanced.
|
||||
*
|
||||
* 5. Incremental Output:
|
||||
* - As soon as the match location is found and we are in the REPLACE section, each new
|
||||
* replacement line is appended to the result so that partial updates can be viewed
|
||||
* incrementally.
|
||||
*
|
||||
* 6. Partial Markers:
|
||||
* - If the final line of the chunk looks like it might be part of a marker but is not one
|
||||
* of the known markers, it is removed. This prevents incomplete or partial markers
|
||||
* from corrupting the output.
|
||||
*
|
||||
* 7. Finalization:
|
||||
* - Once all chunks have been processed (when `isFinal` is true), any remaining original
|
||||
* content after the last replaced section is appended to the result.
|
||||
* - Trailing newlines are not forcibly added. The code tries to output exactly what is specified.
|
||||
*
|
||||
* Errors:
|
||||
* - If the search block cannot be matched using any of the available matching strategies,
|
||||
* an error is thrown.
|
||||
*/
|
||||
export async function constructNewFileContent(diffContent: string, originalContent: string, isFinal: boolean): Promise<string> {
|
||||
let result = ""
|
||||
let lastProcessedIndex = 0
|
||||
|
||||
let currentSearchContent = ""
|
||||
let currentReplaceContent = ""
|
||||
let inSearch = false
|
||||
let inReplace = false
|
||||
|
||||
let searchMatchIndex = -1
|
||||
let searchEndIndex = -1
|
||||
|
||||
let lines = diffContent.split("\n")
|
||||
|
||||
// If the last line looks like a partial marker but isn't recognized,
|
||||
// remove it because it might be incomplete.
|
||||
const lastLine = lines[lines.length - 1]
|
||||
if (
|
||||
lines.length > 0 &&
|
||||
(lastLine.startsWith("<") || lastLine.startsWith("=") || lastLine.startsWith(">")) &&
|
||||
lastLine !== "<<<<<<< SEARCH" &&
|
||||
lastLine !== "=======" &&
|
||||
lastLine !== ">>>>>>> REPLACE"
|
||||
) {
|
||||
lines.pop()
|
||||
}
|
||||
|
||||
for (const line of lines) {
|
||||
if (line === "<<<<<<< SEARCH") {
|
||||
inSearch = true
|
||||
currentSearchContent = ""
|
||||
currentReplaceContent = ""
|
||||
continue
|
||||
}
|
||||
|
||||
if (line === "=======") {
|
||||
inSearch = false
|
||||
inReplace = true
|
||||
|
||||
// Remove trailing linebreak for adding the === marker
|
||||
// if (currentSearchContent.endsWith("\r\n")) {
|
||||
// currentSearchContent = currentSearchContent.slice(0, -2)
|
||||
// } else if (currentSearchContent.endsWith("\n")) {
|
||||
// currentSearchContent = currentSearchContent.slice(0, -1)
|
||||
// }
|
||||
|
||||
if (!currentSearchContent) {
|
||||
// Empty search block
|
||||
if (originalContent.length === 0) {
|
||||
// New file scenario: nothing to match, just start inserting
|
||||
searchMatchIndex = 0
|
||||
searchEndIndex = 0
|
||||
} else {
|
||||
// Complete file replacement scenario: treat the entire file as matched
|
||||
searchMatchIndex = 0
|
||||
searchEndIndex = originalContent.length
|
||||
}
|
||||
} else {
|
||||
// Add check for inefficient full-file search
|
||||
// if (currentSearchContent.trim() === originalContent.trim()) {
|
||||
// throw new Error(
|
||||
// "The SEARCH block contains the entire file content. Please either:\n" +
|
||||
// "1. Use an empty SEARCH block to replace the entire file, or\n" +
|
||||
// "2. Make focused changes to specific parts of the file that need modification.",
|
||||
// )
|
||||
// }
|
||||
|
||||
// Exact search match scenario
|
||||
const exactIndex = originalContent.indexOf(currentSearchContent, lastProcessedIndex)
|
||||
if (exactIndex !== -1) {
|
||||
searchMatchIndex = exactIndex
|
||||
searchEndIndex = exactIndex + currentSearchContent.length
|
||||
} else {
|
||||
// Attempt fallback line-trimmed matching
|
||||
const lineMatch = lineTrimmedFallbackMatch(originalContent, currentSearchContent, lastProcessedIndex)
|
||||
if (lineMatch) {
|
||||
;[searchMatchIndex, searchEndIndex] = lineMatch
|
||||
} else {
|
||||
// Try block anchor fallback for larger blocks
|
||||
const blockMatch = blockAnchorFallbackMatch(originalContent, currentSearchContent, lastProcessedIndex)
|
||||
if (blockMatch) {
|
||||
;[searchMatchIndex, searchEndIndex] = blockMatch
|
||||
} else {
|
||||
throw new Error(
|
||||
`The SEARCH block:\n${currentSearchContent.trimEnd()}\n...does not match anything in the file.`,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Output everything up to the match location
|
||||
result += originalContent.slice(lastProcessedIndex, searchMatchIndex)
|
||||
continue
|
||||
}
|
||||
|
||||
if (line === ">>>>>>> REPLACE") {
|
||||
// Finished one replace block
|
||||
|
||||
// // Remove the artificially added linebreak in the last line of the REPLACE block
|
||||
// if (result.endsWith("\r\n")) {
|
||||
// result = result.slice(0, -2)
|
||||
// } else if (result.endsWith("\n")) {
|
||||
// result = result.slice(0, -1)
|
||||
// }
|
||||
|
||||
// Advance lastProcessedIndex to after the matched section
|
||||
lastProcessedIndex = searchEndIndex
|
||||
|
||||
// Reset for next block
|
||||
inSearch = false
|
||||
inReplace = false
|
||||
currentSearchContent = ""
|
||||
currentReplaceContent = ""
|
||||
searchMatchIndex = -1
|
||||
searchEndIndex = -1
|
||||
continue
|
||||
}
|
||||
|
||||
// Accumulate content for search or replace
|
||||
// (currentReplaceContent is not being used for anything right now since we directly append to result.)
|
||||
// (We artificially add a linebreak since we split on \n at the beginning. In order to not include a trailing linebreak in the final search/result blocks we need to remove it before using them. This allows for partial line matches to be correctly identified.)
|
||||
// NOTE: search/replace blocks must be arranged in the order they appear in the file due to how we build the content using lastProcessedIndex. We also cannot strip the trailing newline since for non-partial lines it would remove the linebreak from the original content. (If we remove end linebreak from search, then we'd also have to remove it from replace but we can't know if it's a partial line or not since the model may be using the line break to indicate the end of the block rather than as part of the search content.) We require the model to output full lines in order for our fallbacks to work as well.
|
||||
if (inSearch) {
|
||||
currentSearchContent += line + "\n"
|
||||
} else if (inReplace) {
|
||||
currentReplaceContent += line + "\n"
|
||||
// Output replacement lines immediately if we know the insertion point
|
||||
if (searchMatchIndex !== -1) {
|
||||
result += line + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this is the final chunk, append any remaining original content
|
||||
if (isFinal && lastProcessedIndex < originalContent.length) {
|
||||
result += originalContent.slice(lastProcessedIndex)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
export type AssistantMessageContent = TextContent | ToolUse
|
||||
|
||||
export { parseAssistantMessage } from "./parse-assistant-message"
|
||||
|
||||
export interface TextContent {
|
||||
type: "text"
|
||||
content: string
|
||||
partial: boolean
|
||||
}
|
||||
|
||||
export const toolUseNames = [
|
||||
"execute_command",
|
||||
"read_file",
|
||||
"write_to_file",
|
||||
"replace_in_file",
|
||||
"search_files",
|
||||
"list_files",
|
||||
"list_code_definition_names",
|
||||
"browser_action",
|
||||
"use_mcp_tool",
|
||||
"access_mcp_resource",
|
||||
"ask_followup_question",
|
||||
"plan_mode_response",
|
||||
"attempt_completion",
|
||||
] as const
|
||||
|
||||
// Converts array of tool call names into a union type ("execute_command" | "read_file" | ...)
|
||||
export type ToolUseName = (typeof toolUseNames)[number]
|
||||
|
||||
export const toolParamNames = [
|
||||
"command",
|
||||
"requires_approval",
|
||||
"path",
|
||||
"content",
|
||||
"diff",
|
||||
"regex",
|
||||
"file_pattern",
|
||||
"recursive",
|
||||
"action",
|
||||
"url",
|
||||
"coordinate",
|
||||
"text",
|
||||
"server_name",
|
||||
"tool_name",
|
||||
"arguments",
|
||||
"uri",
|
||||
"question",
|
||||
"response",
|
||||
"result",
|
||||
] as const
|
||||
|
||||
export type ToolParamName = (typeof toolParamNames)[number]
|
||||
|
||||
export interface ToolUse {
|
||||
type: "tool_use"
|
||||
name: ToolUseName
|
||||
// params is a partial record, allowing only some or none of the possible parameters to be used
|
||||
params: Partial<Record<ToolParamName, string>>
|
||||
partial: boolean
|
||||
}
|
||||
|
||||
export interface ExecuteCommandToolUse extends ToolUse {
|
||||
name: "execute_command"
|
||||
// Pick<Record<ToolParamName, string>, "command"> makes "command" required, but Partial<> makes it optional
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "command" | "requires_approval">>
|
||||
}
|
||||
|
||||
export interface ReadFileToolUse extends ToolUse {
|
||||
name: "read_file"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "path">>
|
||||
}
|
||||
|
||||
export interface WriteToFileToolUse extends ToolUse {
|
||||
name: "write_to_file"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "path" | "content">>
|
||||
}
|
||||
|
||||
export interface ReplaceInFileToolUse extends ToolUse {
|
||||
name: "replace_in_file"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "path" | "diff">>
|
||||
}
|
||||
|
||||
export interface SearchFilesToolUse extends ToolUse {
|
||||
name: "search_files"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "path" | "regex" | "file_pattern">>
|
||||
}
|
||||
|
||||
export interface ListFilesToolUse extends ToolUse {
|
||||
name: "list_files"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "path" | "recursive">>
|
||||
}
|
||||
|
||||
export interface ListCodeDefinitionNamesToolUse extends ToolUse {
|
||||
name: "list_code_definition_names"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "path">>
|
||||
}
|
||||
|
||||
export interface BrowserActionToolUse extends ToolUse {
|
||||
name: "browser_action"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "action" | "url" | "coordinate" | "text">>
|
||||
}
|
||||
|
||||
export interface UseMcpToolToolUse extends ToolUse {
|
||||
name: "use_mcp_tool"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "server_name" | "tool_name" | "arguments">>
|
||||
}
|
||||
|
||||
export interface AccessMcpResourceToolUse extends ToolUse {
|
||||
name: "access_mcp_resource"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "server_name" | "uri">>
|
||||
}
|
||||
|
||||
export interface AskFollowupQuestionToolUse extends ToolUse {
|
||||
name: "ask_followup_question"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "question">>
|
||||
}
|
||||
|
||||
export interface AttemptCompletionToolUse extends ToolUse {
|
||||
name: "attempt_completion"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "result" | "command">>
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import { AssistantMessageContent, TextContent, ToolUse, ToolParamName, toolParamNames, toolUseNames, ToolUseName } from "."
|
||||
|
||||
export function parseAssistantMessage(assistantMessage: string) {
|
||||
let contentBlocks: AssistantMessageContent[] = []
|
||||
let currentTextContent: TextContent | undefined = undefined
|
||||
let currentTextContentStartIndex = 0
|
||||
let currentToolUse: ToolUse | undefined = undefined
|
||||
let currentToolUseStartIndex = 0
|
||||
let currentParamName: ToolParamName | undefined = undefined
|
||||
let currentParamValueStartIndex = 0
|
||||
let accumulator = ""
|
||||
|
||||
for (let i = 0; i < assistantMessage.length; i++) {
|
||||
const char = assistantMessage[i]
|
||||
accumulator += char
|
||||
|
||||
// there should not be a param without a tool use
|
||||
if (currentToolUse && currentParamName) {
|
||||
const currentParamValue = accumulator.slice(currentParamValueStartIndex)
|
||||
const paramClosingTag = `</${currentParamName}>`
|
||||
if (currentParamValue.endsWith(paramClosingTag)) {
|
||||
// end of param value
|
||||
currentToolUse.params[currentParamName] = currentParamValue.slice(0, -paramClosingTag.length).trim()
|
||||
currentParamName = undefined
|
||||
continue
|
||||
} else {
|
||||
// partial param value is accumulating
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// no currentParamName
|
||||
|
||||
if (currentToolUse) {
|
||||
const currentToolValue = accumulator.slice(currentToolUseStartIndex)
|
||||
const toolUseClosingTag = `</${currentToolUse.name}>`
|
||||
if (currentToolValue.endsWith(toolUseClosingTag)) {
|
||||
// end of a tool use
|
||||
currentToolUse.partial = false
|
||||
contentBlocks.push(currentToolUse)
|
||||
currentToolUse = undefined
|
||||
continue
|
||||
} else {
|
||||
const possibleParamOpeningTags = toolParamNames.map((name) => `<${name}>`)
|
||||
for (const paramOpeningTag of possibleParamOpeningTags) {
|
||||
if (accumulator.endsWith(paramOpeningTag)) {
|
||||
// start of a new parameter
|
||||
currentParamName = paramOpeningTag.slice(1, -1) as ToolParamName
|
||||
currentParamValueStartIndex = accumulator.length
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// there's no current param, and not starting a new param
|
||||
|
||||
// special case for write_to_file where file contents could contain the closing tag, in which case the param would have closed and we end up with the rest of the file contents here. To work around this, we get the string between the starting content tag and the LAST content tag.
|
||||
const contentParamName: ToolParamName = "content"
|
||||
if (currentToolUse.name === "write_to_file" && accumulator.endsWith(`</${contentParamName}>`)) {
|
||||
const toolContent = accumulator.slice(currentToolUseStartIndex)
|
||||
const contentStartTag = `<${contentParamName}>`
|
||||
const contentEndTag = `</${contentParamName}>`
|
||||
const contentStartIndex = toolContent.indexOf(contentStartTag) + contentStartTag.length
|
||||
const contentEndIndex = toolContent.lastIndexOf(contentEndTag)
|
||||
if (contentStartIndex !== -1 && contentEndIndex !== -1 && contentEndIndex > contentStartIndex) {
|
||||
currentToolUse.params[contentParamName] = toolContent.slice(contentStartIndex, contentEndIndex).trim()
|
||||
}
|
||||
}
|
||||
|
||||
// partial tool value is accumulating
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// no currentToolUse
|
||||
|
||||
let didStartToolUse = false
|
||||
const possibleToolUseOpeningTags = toolUseNames.map((name) => `<${name}>`)
|
||||
for (const toolUseOpeningTag of possibleToolUseOpeningTags) {
|
||||
if (accumulator.endsWith(toolUseOpeningTag)) {
|
||||
// start of a new tool use
|
||||
currentToolUse = {
|
||||
type: "tool_use",
|
||||
name: toolUseOpeningTag.slice(1, -1) as ToolUseName,
|
||||
params: {},
|
||||
partial: true,
|
||||
}
|
||||
currentToolUseStartIndex = accumulator.length
|
||||
// this also indicates the end of the current text content
|
||||
if (currentTextContent) {
|
||||
currentTextContent.partial = false
|
||||
// remove the partially accumulated tool use tag from the end of text (<tool)
|
||||
currentTextContent.content = currentTextContent.content
|
||||
.slice(0, -toolUseOpeningTag.slice(0, -1).length)
|
||||
.trim()
|
||||
contentBlocks.push(currentTextContent)
|
||||
currentTextContent = undefined
|
||||
}
|
||||
|
||||
didStartToolUse = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!didStartToolUse) {
|
||||
// no tool use, so it must be text either at the beginning or between tools
|
||||
if (currentTextContent === undefined) {
|
||||
currentTextContentStartIndex = i
|
||||
}
|
||||
currentTextContent = {
|
||||
type: "text",
|
||||
content: accumulator.slice(currentTextContentStartIndex).trim(),
|
||||
partial: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentToolUse) {
|
||||
// stream did not complete tool call, add it as partial
|
||||
if (currentParamName) {
|
||||
// tool call has a parameter that was not completed
|
||||
currentToolUse.params[currentParamName] = accumulator.slice(currentParamValueStartIndex).trim()
|
||||
}
|
||||
contentBlocks.push(currentToolUse)
|
||||
}
|
||||
|
||||
// Note: it doesnt matter if check for currentToolUse or currentTextContent, only one of them will be defined since only one can be partial at a time
|
||||
if (currentTextContent) {
|
||||
// stream did not complete text content, add it as partial
|
||||
contentBlocks.push(currentTextContent)
|
||||
}
|
||||
|
||||
return contentBlocks
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
import * as vscode from "vscode"
|
||||
import * as path from "path"
|
||||
import { openFile } from "./open-file"
|
||||
import { UrlContentFetcher } from "./UrlContentFetcher"
|
||||
import { mentionRegexGlobal } from "../shared/context-mentions"
|
||||
import { openFile } from "../../integrations/misc/open-file"
|
||||
import { UrlContentFetcher } from "../../services/browser/UrlContentFetcher"
|
||||
import { mentionRegexGlobal } from "../../shared/context-mentions"
|
||||
import fs from "fs/promises"
|
||||
import { extractTextFromFile } from "./extract-text"
|
||||
import { extractTextFromFile } from "../../integrations/misc/extract-text"
|
||||
import { isBinaryFile } from "isbinaryfile"
|
||||
import { diagnosticsToProblemsString } from "../../integrations/diagnostics"
|
||||
|
||||
export function openMention(mention?: string): void {
|
||||
if (!mention) {
|
||||
@@ -93,8 +94,8 @@ export async function parseMentions(text: string, cwd: string, urlContentFetcher
|
||||
}
|
||||
} else if (mention === "problems") {
|
||||
try {
|
||||
const diagnostics = await getWorkspaceDiagnostics(cwd)
|
||||
parsedText += `\n\n<workspace_diagnostics>\n${diagnostics}\n</workspace_diagnostics>`
|
||||
const problems = getWorkspaceProblems(cwd)
|
||||
parsedText += `\n\n<workspace_diagnostics>\n${problems}\n</workspace_diagnostics>`
|
||||
} catch (error) {
|
||||
parsedText += `\n\n<workspace_diagnostics>\nError fetching diagnostics: ${error.message}\n</workspace_diagnostics>`
|
||||
}
|
||||
@@ -145,11 +146,11 @@ async function getFileOrFolderContent(mentionPath: string, cwd: string): Promise
|
||||
return undefined
|
||||
}
|
||||
const content = await extractTextFromFile(absoluteFilePath)
|
||||
return `<file_content path="${filePath}">\n${content}\n</file_content>`
|
||||
return `<file_content path="${filePath.toPosix()}">\n${content}\n</file_content>`
|
||||
} catch (error) {
|
||||
return undefined
|
||||
}
|
||||
})()
|
||||
})(),
|
||||
)
|
||||
} else if (entry.isDirectory()) {
|
||||
folderContent += `${linePrefix}${entry.name}/\n`
|
||||
@@ -168,28 +169,15 @@ async function getFileOrFolderContent(mentionPath: string, cwd: string): Promise
|
||||
}
|
||||
}
|
||||
|
||||
async function getWorkspaceDiagnostics(cwd: string): Promise<string> {
|
||||
function getWorkspaceProblems(cwd: string): string {
|
||||
const diagnostics = vscode.languages.getDiagnostics()
|
||||
|
||||
let diagnosticsDetails = ""
|
||||
for (const [uri, fileDiagnostics] of diagnostics) {
|
||||
const problems = fileDiagnostics.filter(
|
||||
(d) => d.severity === vscode.DiagnosticSeverity.Error || d.severity === vscode.DiagnosticSeverity.Warning
|
||||
)
|
||||
if (problems.length > 0) {
|
||||
diagnosticsDetails += `\nFile: ${path.relative(cwd, uri.fsPath)}`
|
||||
for (const diagnostic of problems) {
|
||||
let severity = diagnostic.severity === vscode.DiagnosticSeverity.Error ? "Error" : "Warning"
|
||||
const line = diagnostic.range.start.line + 1 // VSCode lines are 0-indexed
|
||||
const source = diagnostic.source ? `${diagnostic.source} ` : ""
|
||||
diagnosticsDetails += `\n- [${source}${severity}] Line ${line}: ${diagnostic.message}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!diagnosticsDetails) {
|
||||
const result = diagnosticsToProblemsString(
|
||||
diagnostics,
|
||||
[vscode.DiagnosticSeverity.Error, vscode.DiagnosticSeverity.Warning],
|
||||
cwd,
|
||||
)
|
||||
if (!result) {
|
||||
return "No errors or warnings detected."
|
||||
}
|
||||
|
||||
return diagnosticsDetails.trim()
|
||||
return result
|
||||
}
|
||||