@react-grab/cursor 0.0.70 → 0.0.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -111,7 +111,7 @@ var import_picocolors = __toESM(require_picocolors());
111
111
  var DEFAULT_PORT = 5567;
112
112
 
113
113
  // src/cli.ts
114
- var VERSION = "0.0.70";
114
+ var VERSION = "0.0.71";
115
115
  var __filename$1 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.cjs', document.baseURI).href)));
116
116
  var __dirname$1 = path.dirname(__filename$1);
117
117
  var serverPath = path.join(__dirname$1, "server.js");
package/dist/cli.js CHANGED
@@ -108,7 +108,7 @@ var import_picocolors = __toESM(require_picocolors());
108
108
  var DEFAULT_PORT = 5567;
109
109
 
110
110
  // src/cli.ts
111
- var VERSION = "0.0.70";
111
+ var VERSION = "0.0.71";
112
112
  var __filename = fileURLToPath(import.meta.url);
113
113
  var __dirname = dirname(__filename);
114
114
  var serverPath = join(__dirname, "server.js");
package/dist/client.cjs CHANGED
@@ -15,13 +15,27 @@ var parseSSEEvent = (eventBlock) => {
15
15
  }
16
16
  return { eventType, data };
17
17
  };
18
- async function* streamSSE(stream) {
18
+ async function* streamSSE(stream, signal) {
19
19
  const reader = stream.getReader();
20
20
  const decoder = new TextDecoder();
21
21
  let buffer = "";
22
+ let aborted = false;
23
+ const onAbort = () => {
24
+ aborted = true;
25
+ reader.cancel().catch(() => {
26
+ });
27
+ };
28
+ signal.addEventListener("abort", onAbort);
22
29
  try {
30
+ if (signal.aborted) {
31
+ throw new DOMException("Aborted", "AbortError");
32
+ }
23
33
  while (true) {
24
- const { done, value } = await reader.read();
34
+ const result = await reader.read();
35
+ if (aborted || signal.aborted) {
36
+ throw new DOMException("Aborted", "AbortError");
37
+ }
38
+ const { done, value } = result;
25
39
  if (value) buffer += decoder.decode(value, { stream: true });
26
40
  let boundary;
27
41
  while ((boundary = buffer.indexOf("\n\n")) !== -1) {
@@ -37,7 +51,11 @@ async function* streamSSE(stream) {
37
51
  if (done) break;
38
52
  }
39
53
  } finally {
40
- reader.releaseLock();
54
+ signal.removeEventListener("abort", onAbort);
55
+ try {
56
+ reader.releaseLock();
57
+ } catch {
58
+ }
41
59
  }
42
60
  }
43
61
  async function* streamFromServer(serverUrl, context, signal) {
@@ -53,7 +71,7 @@ async function* streamFromServer(serverUrl, context, signal) {
53
71
  if (!response.body) {
54
72
  throw new Error("No response body");
55
73
  }
56
- yield* streamSSE(response.body);
74
+ yield* streamSSE(response.body, signal);
57
75
  }
58
76
  var createCursorAgentProvider = (providerOptions = {}) => {
59
77
  const { serverUrl = DEFAULT_SERVER_URL, getOptions } = providerOptions;
@@ -1,4 +1,4 @@
1
- var ReactGrabCursor=(function(exports){'use strict';var l=`http://localhost:${5567}`,f="react-grab:agent-sessions",S=r=>{let t="",n="";for(let e of r.split(`
2
- `))e.startsWith("event:")?t=e.slice(6).trim():e.startsWith("data:")&&(n=e.slice(5).trim());return {eventType:t,data:n}};async function*y(r){let t=r.getReader(),n=new TextDecoder,e="";try{for(;;){let{done:o,value:i}=await t.read();i&&(e+=n.decode(i,{stream:!0}));let s;for(;(s=e.indexOf(`
1
+ var ReactGrabCursor=(function(exports){'use strict';var f=`http://localhost:${5567}`,b="react-grab:agent-sessions",E=o=>{let e="",r="";for(let t of o.split(`
2
+ `))t.startsWith("event:")?e=t.slice(6).trim():t.startsWith("data:")&&(r=t.slice(5).trim());return {eventType:e,data:r}};async function*S(o,e){let r=o.getReader(),t=new TextDecoder,n="",s=false,i=()=>{s=true,r.cancel().catch(()=>{});};e.addEventListener("abort",i);try{if(e.aborted)throw new DOMException("Aborted","AbortError");for(;;){let d=await r.read();if(s||e.aborted)throw new DOMException("Aborted","AbortError");let{done:p,value:c}=d;c&&(n+=t.decode(c,{stream:!0}));let a;for(;(a=n.indexOf(`
3
3
 
4
- `))!==-1;){let{eventType:a,data:c}=S(e.slice(0,s));if(e=e.slice(s+2),a==="done")return;if(a==="error"){console.error("[react-grab]",c||"Agent error");return}c&&(yield c);}if(o)break}}finally{t.releaseLock();}}async function*p(r,t,n){let e=await fetch(`${r}/agent`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),signal:n});if(!e.ok)throw new Error(`Server error: ${e.status}`);if(!e.body)throw new Error("No response body");yield*y(e.body);}var C=(r={})=>{let{serverUrl:t=l,getOptions:n}=r,e=o=>({...n?.()??{},...o??{}});return {send:async function*(o,i){let s={...o,options:e(o.options)};yield*p(t,s,i);},resume:async function*(o,i,s){let a=s.getItem(f);if(!a)throw new Error("No sessions to resume");let g=JSON.parse(a)[o];if(!g)throw new Error(`Session ${o} not found`);let d=g.context,u={...d,options:e(d.options)};yield "Resuming...",yield*p(t,u,i);},supportsResume:true}},E=async()=>{if(typeof window>"u")return;let r=C(),t=window.__REACT_GRAB__;if(t){t.setAgent({provider:r,storage:sessionStorage});return}window.addEventListener("react-grab:init",n=>{n.detail.setAgent({provider:r,storage:sessionStorage});},{once:true});};E();exports.attachAgent=E;exports.createCursorAgentProvider=C;return exports;})({});
4
+ `))!==-1;){let{eventType:g,data:A}=E(n.slice(0,a));if(n=n.slice(a+2),g==="done")return;if(g==="error"){console.error("[react-grab]",A||"Agent error");return}A&&(yield A);}if(p)break}}finally{e.removeEventListener("abort",i);try{r.releaseLock();}catch{}}}async function*u(o,e,r){let t=await fetch(`${o}/agent`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e),signal:r});if(!t.ok)throw new Error(`Server error: ${t.status}`);if(!t.body)throw new Error("No response body");yield*S(t.body,r);}var y=(o={})=>{let{serverUrl:e=f,getOptions:r}=o,t=n=>({...r?.()??{},...n??{}});return {send:async function*(n,s){let i={...n,options:t(n.options)};yield*u(e,i,s);},resume:async function*(n,s,i){let d=i.getItem(b);if(!d)throw new Error("No sessions to resume");let c=JSON.parse(d)[n];if(!c)throw new Error(`Session ${n} not found`);let a=c.context,g={...a,options:t(a.options)};yield "Resuming...",yield*u(e,g,s);},supportsResume:true}},v=async()=>{if(typeof window>"u")return;let o=y(),e=window.__REACT_GRAB__;if(e){e.setAgent({provider:o,storage:sessionStorage});return}window.addEventListener("react-grab:init",r=>{r.detail.setAgent({provider:o,storage:sessionStorage});},{once:true});};v();exports.attachAgent=v;exports.createCursorAgentProvider=y;return exports;})({});
package/dist/client.js CHANGED
@@ -13,13 +13,27 @@ var parseSSEEvent = (eventBlock) => {
13
13
  }
14
14
  return { eventType, data };
15
15
  };
16
- async function* streamSSE(stream) {
16
+ async function* streamSSE(stream, signal) {
17
17
  const reader = stream.getReader();
18
18
  const decoder = new TextDecoder();
19
19
  let buffer = "";
20
+ let aborted = false;
21
+ const onAbort = () => {
22
+ aborted = true;
23
+ reader.cancel().catch(() => {
24
+ });
25
+ };
26
+ signal.addEventListener("abort", onAbort);
20
27
  try {
28
+ if (signal.aborted) {
29
+ throw new DOMException("Aborted", "AbortError");
30
+ }
21
31
  while (true) {
22
- const { done, value } = await reader.read();
32
+ const result = await reader.read();
33
+ if (aborted || signal.aborted) {
34
+ throw new DOMException("Aborted", "AbortError");
35
+ }
36
+ const { done, value } = result;
23
37
  if (value) buffer += decoder.decode(value, { stream: true });
24
38
  let boundary;
25
39
  while ((boundary = buffer.indexOf("\n\n")) !== -1) {
@@ -35,7 +49,11 @@ async function* streamSSE(stream) {
35
49
  if (done) break;
36
50
  }
37
51
  } finally {
38
- reader.releaseLock();
52
+ signal.removeEventListener("abort", onAbort);
53
+ try {
54
+ reader.releaseLock();
55
+ } catch {
56
+ }
39
57
  }
40
58
  }
41
59
  async function* streamFromServer(serverUrl, context, signal) {
@@ -51,7 +69,7 @@ async function* streamFromServer(serverUrl, context, signal) {
51
69
  if (!response.body) {
52
70
  throw new Error("No response body");
53
71
  }
54
- yield* streamSSE(response.body);
72
+ yield* streamSSE(response.body, signal);
55
73
  }
56
74
  var createCursorAgentProvider = (providerOptions = {}) => {
57
75
  const { serverUrl = DEFAULT_SERVER_URL, getOptions } = providerOptions;
package/dist/server.cjs CHANGED
@@ -2366,7 +2366,7 @@ var import_picocolors = __toESM(require_picocolors());
2366
2366
  var DEFAULT_PORT = 5567;
2367
2367
 
2368
2368
  // src/server.ts
2369
- var VERSION = "0.0.70";
2369
+ var VERSION = "0.0.71";
2370
2370
  var parseStreamLine = (line) => {
2371
2371
  const trimmed = line.trim();
2372
2372
  if (!trimmed) return null;
@@ -2389,6 +2389,7 @@ var createServer = () => {
2389
2389
  const fullPrompt = `${prompt}
2390
2390
 
2391
2391
  ${content}`;
2392
+ const requestSignal = context.req.raw.signal;
2392
2393
  return streamSSE(context, async (stream2) => {
2393
2394
  const cursorAgentArgs = [
2394
2395
  "--print",
@@ -2405,11 +2406,17 @@ ${content}`;
2405
2406
  cursorAgentArgs.push("--workspace", process.cwd());
2406
2407
  }
2407
2408
  try {
2408
- await stream2.writeSSE({ data: "Planning next moves", event: "status" });
2409
+ await stream2.writeSSE({ data: "Thinking...", event: "status" });
2409
2410
  const cursorProcess = child_process.spawn("cursor-agent", cursorAgentArgs, {
2410
2411
  stdio: ["pipe", "pipe", "pipe"],
2411
2412
  env: { ...process.env }
2412
2413
  });
2414
+ const killProcess = () => {
2415
+ if (!cursorProcess.killed) {
2416
+ cursorProcess.kill("SIGTERM");
2417
+ }
2418
+ };
2419
+ requestSignal.addEventListener("abort", killProcess);
2413
2420
  let buffer = "";
2414
2421
  const processLine = async (line) => {
2415
2422
  const event = parseStreamLine(line);
@@ -2418,7 +2425,7 @@ ${content}`;
2418
2425
  case "system":
2419
2426
  if (event.subtype === "init") {
2420
2427
  await stream2.writeSSE({
2421
- data: "Planning next moves",
2428
+ data: "Thinking...",
2422
2429
  event: "status"
2423
2430
  });
2424
2431
  }
@@ -2474,13 +2481,15 @@ ${content}`;
2474
2481
  cursorProcess.stdin.end();
2475
2482
  await new Promise((resolve, reject) => {
2476
2483
  cursorProcess.on("close", (code) => {
2477
- if (code === 0) {
2484
+ requestSignal.removeEventListener("abort", killProcess);
2485
+ if (code === 0 || cursorProcess.killed) {
2478
2486
  resolve();
2479
2487
  } else {
2480
2488
  reject(new Error(`cursor-agent exited with code ${code}`));
2481
2489
  }
2482
2490
  });
2483
2491
  cursorProcess.on("error", (error) => {
2492
+ requestSignal.removeEventListener("abort", killProcess);
2484
2493
  reject(error);
2485
2494
  });
2486
2495
  });
package/dist/server.js CHANGED
@@ -2358,7 +2358,7 @@ var import_picocolors = __toESM(require_picocolors());
2358
2358
  var DEFAULT_PORT = 5567;
2359
2359
 
2360
2360
  // src/server.ts
2361
- var VERSION = "0.0.70";
2361
+ var VERSION = "0.0.71";
2362
2362
  var parseStreamLine = (line) => {
2363
2363
  const trimmed = line.trim();
2364
2364
  if (!trimmed) return null;
@@ -2381,6 +2381,7 @@ var createServer = () => {
2381
2381
  const fullPrompt = `${prompt}
2382
2382
 
2383
2383
  ${content}`;
2384
+ const requestSignal = context.req.raw.signal;
2384
2385
  return streamSSE(context, async (stream2) => {
2385
2386
  const cursorAgentArgs = [
2386
2387
  "--print",
@@ -2397,11 +2398,17 @@ ${content}`;
2397
2398
  cursorAgentArgs.push("--workspace", process.cwd());
2398
2399
  }
2399
2400
  try {
2400
- await stream2.writeSSE({ data: "Planning next moves", event: "status" });
2401
+ await stream2.writeSSE({ data: "Thinking...", event: "status" });
2401
2402
  const cursorProcess = spawn("cursor-agent", cursorAgentArgs, {
2402
2403
  stdio: ["pipe", "pipe", "pipe"],
2403
2404
  env: { ...process.env }
2404
2405
  });
2406
+ const killProcess = () => {
2407
+ if (!cursorProcess.killed) {
2408
+ cursorProcess.kill("SIGTERM");
2409
+ }
2410
+ };
2411
+ requestSignal.addEventListener("abort", killProcess);
2405
2412
  let buffer = "";
2406
2413
  const processLine = async (line) => {
2407
2414
  const event = parseStreamLine(line);
@@ -2410,7 +2417,7 @@ ${content}`;
2410
2417
  case "system":
2411
2418
  if (event.subtype === "init") {
2412
2419
  await stream2.writeSSE({
2413
- data: "Planning next moves",
2420
+ data: "Thinking...",
2414
2421
  event: "status"
2415
2422
  });
2416
2423
  }
@@ -2466,13 +2473,15 @@ ${content}`;
2466
2473
  cursorProcess.stdin.end();
2467
2474
  await new Promise((resolve, reject) => {
2468
2475
  cursorProcess.on("close", (code) => {
2469
- if (code === 0) {
2476
+ requestSignal.removeEventListener("abort", killProcess);
2477
+ if (code === 0 || cursorProcess.killed) {
2470
2478
  resolve();
2471
2479
  } else {
2472
2480
  reject(new Error(`cursor-agent exited with code ${code}`));
2473
2481
  }
2474
2482
  });
2475
2483
  cursorProcess.on("error", (error) => {
2484
+ requestSignal.removeEventListener("abort", killProcess);
2476
2485
  reject(error);
2477
2486
  });
2478
2487
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-grab/cursor",
3
- "version": "0.0.70",
3
+ "version": "0.0.71",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "react-grab-cursor": "./dist/cli.js"
@@ -30,7 +30,7 @@
30
30
  "@hono/node-server": "^1.19.6",
31
31
  "hono": "^4.0.0",
32
32
  "picocolors": "^1.1.1",
33
- "react-grab": "0.0.70"
33
+ "react-grab": "0.0.71"
34
34
  },
35
35
  "scripts": {
36
36
  "dev": "tsup --watch",