Skip to content
This repository was archived by the owner on Feb 18, 2025. It is now read-only.

Commit 41aed66

Browse files
ktiaysunixzii
authored andcommitted
Adapt to the new version of Cursor API
1 parent 0e52ce7 commit 41aed66

10 files changed

Lines changed: 93 additions & 229 deletions

File tree

crates/cursor-core/src/auth/mod.rs

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// pub mod session;
21
pub mod token;
32

43
use std::future::IntoFuture;
@@ -16,10 +15,13 @@ use uuid::Uuid;
1615
use wasm_bindgen::prelude::*;
1716
use wasm_bindgen_futures::future_to_promise;
1817

18+
const AUTH_TOKEN_KEY: &str = "auth_token";
19+
1920
use crate::{
2021
bindings::{progress_location::ProgressLocation, progress_options::ProgressOptions},
2122
context::get_extension_context,
2223
request::make_request,
24+
storage::GlobalStorage,
2325
};
2426

2527
use self::token::Token;
@@ -53,6 +55,14 @@ where
5355

5456
#[wasm_bindgen(js_name = signIn)]
5557
pub async fn sign_in() {
58+
let context = get_extension_context();
59+
let storage = context.storage();
60+
if storage.get(AUTH_TOKEN_KEY).is_some() {
61+
// If there is already an authentication token, it means that the user has logged in
62+
// and does not need to log in again.
63+
return;
64+
}
65+
5666
let uuid = Uuid::new_v4().to_string();
5767
let verifier = base64_encode(random_bytes());
5868
let challenge = base64_encode(sha256(verifier.clone()));
@@ -62,7 +72,6 @@ pub async fn sign_in() {
6272
uuid.clone()
6373
);
6474

65-
let context = get_extension_context();
6675
// The API of VSCode does not allow us to obtain the execution result of the 'vscode.open' command,
6776
// so we cannot determine whether the user has confirmed to open url.
6877
context
@@ -73,16 +82,18 @@ pub async fn sign_in() {
7382
.with_progress(
7483
ProgressOptions {
7584
location: ProgressLocation::Notification,
76-
title: Some("Signing in...".to_owned()),
85+
title: Some("Signing In/Up...".to_owned()),
7786
cancellable: true,
7887
},
7988
closure!(|abort_signal: AbortSignal| {
8089
let uuid = uuid.clone();
8190
let verifier = verifier.clone();
91+
let storage: GlobalStorage = storage.clone().into();
8292
future_to_promise(async move {
83-
polling(&uuid, &verifier, abort_signal)
84-
.await
85-
.map(Into::into)
93+
if let Some(token) = polling(&uuid, &verifier, abort_signal).await? {
94+
storage.update(AUTH_TOKEN_KEY, Some(&token));
95+
}
96+
Ok(JsValue::null())
8697
})
8798
})
8899
.into_js_value()
@@ -151,13 +162,47 @@ async fn polling(
151162
}
152163
}
153164

154-
pub fn sign_out() {}
165+
#[wasm_bindgen(js_name = signOut)]
166+
pub fn sign_out() {
167+
get_extension_context()
168+
.storage()
169+
.update(AUTH_TOKEN_KEY, None);
170+
}
171+
172+
pub fn account_token() -> Option<Token> {
173+
get_extension_context()
174+
.storage()
175+
.get(AUTH_TOKEN_KEY)
176+
.and_then(|token| serde_json::from_str(&token).ok())
177+
}
155178

156179
#[cfg(test)]
157180
mod test {
181+
use super::*;
182+
158183
#[test]
159184
fn test_random_bytes() {
160185
let bytes = super::random_bytes();
161186
assert_eq!(bytes.len(), 32);
162187
}
188+
189+
#[test]
190+
fn test_base64_encode() {
191+
let bytes = vec![
192+
0xa9, 0x1e, 0x74, 0x36, 0x4a, 0x57, 0xb6, 0x40, 0xcf, 0x25, 0x37, 0xf7, 0x20, 0x26,
193+
0x7a, 0x2e, 0x94, 0x90, 0x03, 0x85, 0x5b, 0xb8, 0xd0, 0x92, 0x37, 0xdc, 0xb3, 0xd9,
194+
0x0a, 0x4d, 0xd4, 0xc5,
195+
];
196+
let encoded = base64_encode(bytes);
197+
assert_eq!(encoded, "qR50NkpXtkDPJTf3ICZ6LpSQA4VbuNCSN9yz2QpN1MU");
198+
}
199+
200+
#[test]
201+
fn test_sha256() {
202+
let v = "qR50NkpXtkDPJTf3ICZ6LpSQA4VbuNCSN9yz2QpN1MU";
203+
assert_eq!(
204+
base64_encode(sha256(v)),
205+
"ddiNacYgAjUZTDf6Pza1wRlSjuWIQRz5Z1Jc2Bj4DII"
206+
);
207+
}
163208
}

crates/cursor-core/src/auth/session.rs

Lines changed: 0 additions & 57 deletions
This file was deleted.

crates/cursor-core/src/auth/token.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use serde::{Deserialize, Serialize};
22

3-
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
3+
#[derive(Debug, Clone, Serialize, Deserialize)]
44
#[serde(rename_all = "camelCase")]
55
pub struct Token {
66
pub access_token: String,

crates/cursor-core/src/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ extern "C" {
1717
#[wasm_bindgen(typescript_type = "IExtensionContext")]
1818
pub type ExtensionContext;
1919

20-
#[wasm_bindgen(method, structural)]
20+
#[wasm_bindgen(method, structural, getter)]
2121
pub fn storage(this: &ExtensionContext) -> GlobalStorage;
2222

2323
#[wasm_bindgen(method, structural, js_name = executeCommand)]

crates/cursor-core/src/conversation/chat/session.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ impl Session {
6969

7070
pub async fn send_message(&mut self, input: &GenerateInput) -> Result<(), JsValue> {
7171
let request_body = self.body_with_input(input);
72-
let mut state = make_conversation_request("/conversation", request_body, true).await?;
72+
let mut state = make_conversation_request("/conversation", request_body).await?;
7373

7474
let mut message: String = "".to_owned();
7575

crates/cursor-core/src/conversation/generate/mod.rs

Lines changed: 14 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -6,100 +6,44 @@ use futures::{
66
};
77
use node_bridge::futures::Defer;
88
use node_bridge::prelude::*;
9-
use uuid::Uuid;
109
use wasm_bindgen::prelude::*;
1110

1211
use crate::GenerateInput;
1312

1413
use super::{
1514
make_conversation_request,
16-
models::{BotMessage, MessageType, RequestBody},
15+
models::{MessageType, RequestBody},
1716
};
1817

1918
async fn generate_code_inner(input: &GenerateInput) -> Result<(), JsValue> {
20-
let file_path = input.file_path();
2119
let selection = input.selection_range();
2220

2321
let message_type = if selection.is_empty() {
2422
MessageType::Generate
2523
} else {
2624
MessageType::Edit
2725
};
28-
let mut request_body = RequestBody::new_with_input(input, message_type);
29-
26+
let request_body = RequestBody::new_with_input(input, message_type);
3027
let result_stream = input.result_stream();
3128

32-
let mut conversation_id: Option<String> = None;
33-
// The last message received from the server.
34-
let mut previous_message: String = "".to_owned();
35-
let mut last_token = "".to_owned();
36-
37-
// If the conversation was interrupted, we need to send a "continue" request.
38-
let mut interrupted = false;
39-
40-
loop {
41-
#[cfg(debug_assertions)]
42-
console::log_str(&serde_json::to_string(&request_body).unwrap());
43-
44-
let mut state = make_conversation_request(
45-
if interrupted {
46-
"/continue/"
47-
} else {
48-
"/conversation"
49-
},
50-
&request_body,
51-
!interrupted,
52-
)
53-
.await?;
54-
interrupted = false;
55-
56-
#[cfg(debug_assertions)]
57-
console::log_str("response received");
58-
59-
let mut data_stream = state.data_stream();
60-
while let Some(mut data) = data_stream.next().await {
61-
if data.contains("<|END_interrupt|>") {
62-
interrupted = true;
63-
last_token = data.clone();
64-
// `END_interrupt` is included in valid data,
65-
// we cannot discard it.
66-
data = data.replace("<|END_interrupt|>", "");
67-
}
68-
previous_message.push_str(&data);
69-
result_stream.write(&data);
70-
71-
#[cfg(debug_assertions)]
72-
console::log_str(&format!("wrote: {}", &data));
73-
}
74-
drop(data_stream);
29+
#[cfg(debug_assertions)]
30+
console::log_str(&serde_json::to_string(&request_body).unwrap());
7531

76-
// Make sure the response is fully received without errors.
77-
state.complete().await?;
32+
let mut state = make_conversation_request("/conversation", &request_body).await?;
7833

79-
if !interrupted {
80-
break;
81-
}
34+
#[cfg(debug_assertions)]
35+
console::log_str("response received");
8236

37+
let mut data_stream = state.data_stream();
38+
while let Some(data) = data_stream.next().await {
39+
result_stream.write(&data);
8340
#[cfg(debug_assertions)]
84-
console::log_str("generation interrupted");
85-
86-
// Generate an UUID as conversation ID.
87-
if conversation_id.is_none() {
88-
conversation_id = Some(Uuid::new_v4().to_string());
89-
}
90-
let bot_message = BotMessage::new(
91-
conversation_id.clone().unwrap(),
92-
message_type,
93-
previous_message.clone(),
94-
last_token.clone(),
95-
file_path.to_owned(),
96-
false,
97-
);
98-
request_body.bot_messages = vec![bot_message];
41+
console::log_str(&format!("wrote: {}", &data));
9942
}
43+
drop(data_stream);
10044

101-
console::log_str("generate done");
102-
45+
// Make sure the response is fully received without errors.
46+
state.complete().await?;
10347
result_stream.end();
10448
Ok(())
10549
}

0 commit comments

Comments
 (0)