@rama_nigg/open-cursor 2.3.10 → 2.3.12

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.
@@ -1,13 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
3
  var __defProp = Object.defineProperty;
4
+ var __returnValue = (v) => v;
5
+ function __exportSetter(name, newValue) {
6
+ this[name] = __returnValue.bind(null, newValue);
7
+ }
4
8
  var __export = (target, all) => {
5
9
  for (var name in all)
6
10
  __defProp(target, name, {
7
11
  get: all[name],
8
12
  enumerable: true,
9
13
  configurable: true,
10
- set: (newValue) => all[name] = () => newValue
14
+ set: __exportSetter.bind(all, name)
11
15
  });
12
16
  };
13
17
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -1,13 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
3
  var __defProp = Object.defineProperty;
4
+ var __returnValue = (v) => v;
5
+ function __exportSetter(name, newValue) {
6
+ this[name] = __returnValue.bind(null, newValue);
7
+ }
4
8
  var __export = (target, all) => {
5
9
  for (var name in all)
6
10
  __defProp(target, name, {
7
11
  get: all[name],
8
12
  enumerable: true,
9
13
  configurable: true,
10
- set: (newValue) => all[name] = () => newValue
14
+ set: __exportSetter.bind(all, name)
11
15
  });
12
16
  };
13
17
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
package/dist/index.js CHANGED
@@ -1,12 +1,16 @@
1
1
  import { createRequire } from "node:module";
2
2
  var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
3
7
  var __export = (target, all) => {
4
8
  for (var name in all)
5
9
  __defProp(target, name, {
6
10
  get: all[name],
7
11
  enumerable: true,
8
12
  configurable: true,
9
- set: (newValue) => all[name] = () => newValue
13
+ set: __exportSetter.bind(all, name)
10
14
  });
11
15
  };
12
16
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -13331,7 +13335,15 @@ class DeltaTracker {
13331
13335
  if (current.startsWith(previous)) {
13332
13336
  return current.slice(previous.length);
13333
13337
  }
13334
- return current;
13338
+ if (previous.startsWith(current)) {
13339
+ return "";
13340
+ }
13341
+ let i = 0;
13342
+ const minLen = Math.min(previous.length, current.length);
13343
+ while (i < minLen && previous[i] === current[i]) {
13344
+ i++;
13345
+ }
13346
+ return current.slice(i);
13335
13347
  }
13336
13348
  }
13337
13349
 
@@ -13341,6 +13353,8 @@ class StreamToSseConverter {
13341
13353
  created;
13342
13354
  model;
13343
13355
  tracker = new DeltaTracker;
13356
+ sawAssistantPartials = false;
13357
+ sawThinkingPartials = false;
13344
13358
  constructor(model, options) {
13345
13359
  this.model = model;
13346
13360
  this.id = options?.id ?? `cursor-acp-${Date.now()}`;
@@ -13348,10 +13362,28 @@ class StreamToSseConverter {
13348
13362
  }
13349
13363
  handleEvent(event) {
13350
13364
  if (isAssistantText(event)) {
13365
+ const isPartial = typeof event.timestamp_ms === "number";
13366
+ if (isPartial) {
13367
+ this.sawAssistantPartials = true;
13368
+ const text = extractText(event);
13369
+ return text ? [this.chunkWith({ content: text })] : [];
13370
+ }
13371
+ if (this.sawAssistantPartials) {
13372
+ return [];
13373
+ }
13351
13374
  const delta = this.tracker.nextText(extractText(event));
13352
13375
  return delta ? [this.chunkWith({ content: delta })] : [];
13353
13376
  }
13354
13377
  if (isThinking(event)) {
13378
+ const isPartial = typeof event.timestamp_ms === "number";
13379
+ if (isPartial) {
13380
+ this.sawThinkingPartials = true;
13381
+ const text = extractThinking(event);
13382
+ return text ? [this.chunkWith({ reasoning_content: text })] : [];
13383
+ }
13384
+ if (this.sawThinkingPartials) {
13385
+ return [];
13386
+ }
13355
13387
  const delta = this.tracker.nextThinking(extractThinking(event));
13356
13388
  return delta ? [this.chunkWith({ reasoning_content: delta })] : [];
13357
13389
  }
@@ -19846,12 +19878,32 @@ class StreamToAiSdkParts {
19846
19878
  tracker = new DeltaTracker;
19847
19879
  toolArgsById = new Map;
19848
19880
  startedToolIds = new Set;
19881
+ sawAssistantPartials = false;
19882
+ sawThinkingPartials = false;
19849
19883
  handleEvent(event) {
19850
19884
  if (isAssistantText(event)) {
19885
+ const isPartial = typeof event.timestamp_ms === "number";
19886
+ if (isPartial) {
19887
+ this.sawAssistantPartials = true;
19888
+ const text = extractText(event);
19889
+ return text ? [{ type: "text-delta", textDelta: text }] : [];
19890
+ }
19891
+ if (this.sawAssistantPartials) {
19892
+ return [];
19893
+ }
19851
19894
  const delta = this.tracker.nextText(extractText(event));
19852
19895
  return delta ? [{ type: "text-delta", textDelta: delta }] : [];
19853
19896
  }
19854
19897
  if (isThinking(event)) {
19898
+ const isPartial = typeof event.timestamp_ms === "number";
19899
+ if (isPartial) {
19900
+ this.sawThinkingPartials = true;
19901
+ const text = extractThinking(event);
19902
+ return text ? [{ type: "text-delta", textDelta: text }] : [];
19903
+ }
19904
+ if (this.sawThinkingPartials) {
19905
+ return [];
19906
+ }
19855
19907
  const delta = this.tracker.nextThinking(extractThinking(event));
19856
19908
  return delta ? [{ type: "text-delta", textDelta: delta }] : [];
19857
19909
  }
@@ -1,12 +1,16 @@
1
1
  import { createRequire } from "node:module";
2
2
  var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
3
7
  var __export = (target, all) => {
4
8
  for (var name in all)
5
9
  __defProp(target, name, {
6
10
  get: all[name],
7
11
  enumerable: true,
8
12
  configurable: true,
9
- set: (newValue) => all[name] = () => newValue
13
+ set: __exportSetter.bind(all, name)
10
14
  });
11
15
  };
12
16
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -13331,7 +13335,15 @@ class DeltaTracker {
13331
13335
  if (current.startsWith(previous)) {
13332
13336
  return current.slice(previous.length);
13333
13337
  }
13334
- return current;
13338
+ if (previous.startsWith(current)) {
13339
+ return "";
13340
+ }
13341
+ let i = 0;
13342
+ const minLen = Math.min(previous.length, current.length);
13343
+ while (i < minLen && previous[i] === current[i]) {
13344
+ i++;
13345
+ }
13346
+ return current.slice(i);
13335
13347
  }
13336
13348
  }
13337
13349
 
@@ -13341,6 +13353,8 @@ class StreamToSseConverter {
13341
13353
  created;
13342
13354
  model;
13343
13355
  tracker = new DeltaTracker;
13356
+ sawAssistantPartials = false;
13357
+ sawThinkingPartials = false;
13344
13358
  constructor(model, options) {
13345
13359
  this.model = model;
13346
13360
  this.id = options?.id ?? `cursor-acp-${Date.now()}`;
@@ -13348,10 +13362,28 @@ class StreamToSseConverter {
13348
13362
  }
13349
13363
  handleEvent(event) {
13350
13364
  if (isAssistantText(event)) {
13365
+ const isPartial = typeof event.timestamp_ms === "number";
13366
+ if (isPartial) {
13367
+ this.sawAssistantPartials = true;
13368
+ const text = extractText(event);
13369
+ return text ? [this.chunkWith({ content: text })] : [];
13370
+ }
13371
+ if (this.sawAssistantPartials) {
13372
+ return [];
13373
+ }
13351
13374
  const delta = this.tracker.nextText(extractText(event));
13352
13375
  return delta ? [this.chunkWith({ content: delta })] : [];
13353
13376
  }
13354
13377
  if (isThinking(event)) {
13378
+ const isPartial = typeof event.timestamp_ms === "number";
13379
+ if (isPartial) {
13380
+ this.sawThinkingPartials = true;
13381
+ const text = extractThinking(event);
13382
+ return text ? [this.chunkWith({ reasoning_content: text })] : [];
13383
+ }
13384
+ if (this.sawThinkingPartials) {
13385
+ return [];
13386
+ }
13355
13387
  const delta = this.tracker.nextThinking(extractThinking(event));
13356
13388
  return delta ? [this.chunkWith({ reasoning_content: delta })] : [];
13357
13389
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rama_nigg/open-cursor",
3
- "version": "2.3.10",
3
+ "version": "2.3.12",
4
4
  "description": "No prompt limits. No broken streams. Full thinking + tool support. Your Cursor subscription, properly integrated.",
5
5
  "type": "module",
6
6
  "main": "dist/plugin-entry.js",
@@ -37,14 +37,34 @@ export class StreamToAiSdkParts {
37
37
  private readonly tracker = new DeltaTracker();
38
38
  private readonly toolArgsById = new Map<string, string>();
39
39
  private readonly startedToolIds = new Set<string>();
40
+ private sawAssistantPartials = false;
41
+ private sawThinkingPartials = false;
40
42
 
41
43
  handleEvent(event: StreamJsonEvent): AiSdkStreamPart[] {
42
44
  if (isAssistantText(event)) {
45
+ const isPartial = typeof (event as any).timestamp_ms === "number";
46
+ if (isPartial) {
47
+ this.sawAssistantPartials = true;
48
+ const text = extractText(event);
49
+ return text ? [{ type: "text-delta", textDelta: text }] : [];
50
+ }
51
+ if (this.sawAssistantPartials) {
52
+ return [];
53
+ }
43
54
  const delta = this.tracker.nextText(extractText(event));
44
55
  return delta ? [{ type: "text-delta", textDelta: delta }] : [];
45
56
  }
46
57
 
47
58
  if (isThinking(event)) {
59
+ const isPartial = typeof (event as any).timestamp_ms === "number";
60
+ if (isPartial) {
61
+ this.sawThinkingPartials = true;
62
+ const text = extractThinking(event);
63
+ return text ? [{ type: "text-delta", textDelta: text }] : [];
64
+ }
65
+ if (this.sawThinkingPartials) {
66
+ return [];
67
+ }
48
68
  const delta = this.tracker.nextThinking(extractThinking(event));
49
69
  return delta ? [{ type: "text-delta", textDelta: delta }] : [];
50
70
  }
@@ -24,10 +24,24 @@ export class DeltaTracker {
24
24
  return current;
25
25
  }
26
26
 
27
+ // Happy path: accumulated text grows with exact prefix match
27
28
  if (current.startsWith(previous)) {
28
29
  return current.slice(previous.length);
29
30
  }
30
31
 
31
- return current;
32
+ // Accumulated text was already fully emitted (e.g. duplicate or trimmed event)
33
+ if (previous.startsWith(current)) {
34
+ return "";
35
+ }
36
+
37
+ // Prefix mismatch (formatting drift, unicode normalization, whitespace changes):
38
+ // find longest common prefix and emit only the new suffix.
39
+ // This prevents re-emitting the entire accumulated text as a "delta".
40
+ let i = 0;
41
+ const minLen = Math.min(previous.length, current.length);
42
+ while (i < minLen && previous[i] === current[i]) {
43
+ i++;
44
+ }
45
+ return current.slice(i);
32
46
  }
33
47
  }
@@ -61,6 +61,11 @@ export class StreamToSseConverter {
61
61
  private readonly created: number;
62
62
  private readonly model: string;
63
63
  private readonly tracker = new DeltaTracker();
64
+ // Events with timestamp_ms carry delta text; events without carry accumulated text.
65
+ // DeltaTracker handles accumulated text only. When partials (delta) were seen,
66
+ // the final accumulated event must be skipped to prevent 2x duplication.
67
+ private sawAssistantPartials = false;
68
+ private sawThinkingPartials = false;
64
69
 
65
70
  constructor(model: string, options?: { id?: string; created?: number }) {
66
71
  this.model = model;
@@ -70,11 +75,29 @@ export class StreamToSseConverter {
70
75
 
71
76
  handleEvent(event: StreamJsonEvent): string[] {
72
77
  if (isAssistantText(event)) {
78
+ const isPartial = typeof (event as any).timestamp_ms === "number";
79
+ if (isPartial) {
80
+ this.sawAssistantPartials = true;
81
+ const text = extractText(event);
82
+ return text ? [this.chunkWith({ content: text })] : [];
83
+ }
84
+ if (this.sawAssistantPartials) {
85
+ return [];
86
+ }
73
87
  const delta = this.tracker.nextText(extractText(event));
74
88
  return delta ? [this.chunkWith({ content: delta })] : [];
75
89
  }
76
90
 
77
91
  if (isThinking(event)) {
92
+ const isPartial = typeof (event as any).timestamp_ms === "number";
93
+ if (isPartial) {
94
+ this.sawThinkingPartials = true;
95
+ const text = extractThinking(event);
96
+ return text ? [this.chunkWith({ reasoning_content: text })] : [];
97
+ }
98
+ if (this.sawThinkingPartials) {
99
+ return [];
100
+ }
78
101
  const delta = this.tracker.nextThinking(extractThinking(event));
79
102
  return delta ? [this.chunkWith({ reasoning_content: delta })] : [];
80
103
  }