@rama_nigg/open-cursor 2.4.1 → 2.4.3

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.
@@ -377,6 +377,7 @@ import {
377
377
  existsSync as existsSync2,
378
378
  lstatSync,
379
379
  mkdirSync as mkdirSync2,
380
+ realpathSync,
380
381
  readFileSync,
381
382
  rmSync,
382
383
  symlinkSync,
@@ -1634,13 +1635,33 @@ function main() {
1634
1635
  process.exit(1);
1635
1636
  }
1636
1637
  }
1637
- if (fileURLToPath(import.meta.url) === resolve(process.argv[1] || "")) {
1638
+ function resolveEntrypointArg(argvPath) {
1639
+ if (!argvPath)
1640
+ return "";
1641
+ return resolve(argvPath);
1642
+ }
1643
+ function toRealPath(path2) {
1644
+ try {
1645
+ return realpathSync(path2);
1646
+ } catch {
1647
+ return path2;
1648
+ }
1649
+ }
1650
+ function isCliEntrypoint(metaUrl, argvPath) {
1651
+ const currentPath = fileURLToPath(metaUrl);
1652
+ const argvResolved = resolveEntrypointArg(argvPath);
1653
+ if (!argvResolved)
1654
+ return false;
1655
+ return currentPath === argvResolved || toRealPath(currentPath) === toRealPath(argvResolved);
1656
+ }
1657
+ if (isCliEntrypoint(import.meta.url, process.argv[1])) {
1638
1658
  main();
1639
1659
  }
1640
1660
  export {
1641
1661
  summarizeModelSync,
1642
1662
  runDoctorChecks,
1643
1663
  runDeepDoctorChecks,
1664
+ isCliEntrypoint,
1644
1665
  getStatusResult,
1645
1666
  getBrandingHeader,
1646
1667
  explainCursorModels,
package/dist/index.js CHANGED
@@ -14563,8 +14563,8 @@ function normalizeToolSpecificArgs(toolName, args) {
14563
14563
  if (!hasStringNew && typeof content === "string") {
14564
14564
  repaired.new_string = content;
14565
14565
  }
14566
- if (typeof repaired.new_string === "string" && !hasStringOld) {
14567
- repaired.old_string = "";
14566
+ if (hasStringOld && repaired.old_string === "") {
14567
+ delete repaired.old_string;
14568
14568
  }
14569
14569
  return repaired;
14570
14570
  }
@@ -14867,15 +14867,7 @@ async function handleToolLoopEventLegacy(options) {
14867
14867
  }
14868
14868
  return { intercepted: false, skipConverter: true, terminate: validationTermination };
14869
14869
  }
14870
- const reroutedWrite = tryRerouteEditToWrite(normalizedToolCall, compat.normalizedArgs, allowedToolNames, toolSchemaMap);
14871
- if (reroutedWrite) {
14872
- log18.debug("Rerouting malformed edit call to write (legacy)", {
14873
- path: reroutedWrite.path,
14874
- missing: compat.validation.missing,
14875
- typeErrors: compat.validation.typeErrors
14876
- });
14877
- normalizedToolCall = reroutedWrite.toolCall;
14878
- } else if (shouldEmitNonFatalSchemaValidationHint(normalizedToolCall, compat.validation)) {
14870
+ if (shouldEmitNonFatalSchemaValidationHint(normalizedToolCall, compat.validation)) {
14879
14871
  const hintChunk = createNonFatalSchemaValidationHintChunk(responseMeta, normalizedToolCall, compat.validation);
14880
14872
  log18.debug("Emitting non-fatal schema validation hint in legacy and skipping malformed tool execution", {
14881
14873
  tool: normalizedToolCall.function.name,
@@ -15019,19 +15011,6 @@ async function handleToolLoopEventV1(options) {
15019
15011
  }
15020
15012
  return { intercepted: false, skipConverter: true, terminate: termination2 };
15021
15013
  }
15022
- const reroutedWrite = tryRerouteEditToWrite(normalizedToolCall, compat.normalizedArgs, allowedToolNames, toolSchemaMap);
15023
- if (reroutedWrite) {
15024
- log18.debug("Rerouting malformed edit call to write", {
15025
- path: reroutedWrite.path,
15026
- missing: compat.validation.missing,
15027
- typeErrors: compat.validation.typeErrors
15028
- });
15029
- await onInterceptedToolCall(reroutedWrite.toolCall);
15030
- return {
15031
- intercepted: true,
15032
- skipConverter: true
15033
- };
15034
- }
15035
15014
  if (schemaValidationFailureMode === "pass_through" && shouldTerminateOnSchemaValidation(normalizedToolCall, compat.validation)) {
15036
15015
  return {
15037
15016
  intercepted: false,
@@ -15341,36 +15320,6 @@ function shouldUsePassThroughForEditSchema(event) {
15341
15320
  const normalizedName = rawName.endsWith("ToolCall") ? rawName.slice(0, -"ToolCall".length) : rawName;
15342
15321
  return normalizedName.toLowerCase() === "edit";
15343
15322
  }
15344
- function tryRerouteEditToWrite(toolCall, normalizedArgs, allowedToolNames, toolSchemaMap) {
15345
- if (toolCall.function.name.toLowerCase() !== "edit") {
15346
- return null;
15347
- }
15348
- if (!allowedToolNames.has("write") || !toolSchemaMap.has("write")) {
15349
- return null;
15350
- }
15351
- const path2 = typeof normalizedArgs.path === "string" && normalizedArgs.path.length > 0 ? normalizedArgs.path : null;
15352
- if (!path2) {
15353
- return null;
15354
- }
15355
- const content = typeof normalizedArgs.new_string === "string" ? normalizedArgs.new_string : typeof normalizedArgs.content === "string" ? normalizedArgs.content : null;
15356
- if (content === null) {
15357
- return null;
15358
- }
15359
- const oldString = normalizedArgs.old_string;
15360
- if (typeof oldString === "string" && oldString.length > 0) {
15361
- return null;
15362
- }
15363
- return {
15364
- path: path2,
15365
- toolCall: {
15366
- ...toolCall,
15367
- function: {
15368
- name: "write",
15369
- arguments: JSON.stringify({ path: path2, content })
15370
- }
15371
- }
15372
- };
15373
- }
15374
15323
  function isRecord4(value) {
15375
15324
  return typeof value === "object" && value !== null && !Array.isArray(value);
15376
15325
  }
@@ -14563,8 +14563,8 @@ function normalizeToolSpecificArgs(toolName, args) {
14563
14563
  if (!hasStringNew && typeof content === "string") {
14564
14564
  repaired.new_string = content;
14565
14565
  }
14566
- if (typeof repaired.new_string === "string" && !hasStringOld) {
14567
- repaired.old_string = "";
14566
+ if (hasStringOld && repaired.old_string === "") {
14567
+ delete repaired.old_string;
14568
14568
  }
14569
14569
  return repaired;
14570
14570
  }
@@ -14867,15 +14867,7 @@ async function handleToolLoopEventLegacy(options) {
14867
14867
  }
14868
14868
  return { intercepted: false, skipConverter: true, terminate: validationTermination };
14869
14869
  }
14870
- const reroutedWrite = tryRerouteEditToWrite(normalizedToolCall, compat.normalizedArgs, allowedToolNames, toolSchemaMap);
14871
- if (reroutedWrite) {
14872
- log18.debug("Rerouting malformed edit call to write (legacy)", {
14873
- path: reroutedWrite.path,
14874
- missing: compat.validation.missing,
14875
- typeErrors: compat.validation.typeErrors
14876
- });
14877
- normalizedToolCall = reroutedWrite.toolCall;
14878
- } else if (shouldEmitNonFatalSchemaValidationHint(normalizedToolCall, compat.validation)) {
14870
+ if (shouldEmitNonFatalSchemaValidationHint(normalizedToolCall, compat.validation)) {
14879
14871
  const hintChunk = createNonFatalSchemaValidationHintChunk(responseMeta, normalizedToolCall, compat.validation);
14880
14872
  log18.debug("Emitting non-fatal schema validation hint in legacy and skipping malformed tool execution", {
14881
14873
  tool: normalizedToolCall.function.name,
@@ -15019,19 +15011,6 @@ async function handleToolLoopEventV1(options) {
15019
15011
  }
15020
15012
  return { intercepted: false, skipConverter: true, terminate: termination2 };
15021
15013
  }
15022
- const reroutedWrite = tryRerouteEditToWrite(normalizedToolCall, compat.normalizedArgs, allowedToolNames, toolSchemaMap);
15023
- if (reroutedWrite) {
15024
- log18.debug("Rerouting malformed edit call to write", {
15025
- path: reroutedWrite.path,
15026
- missing: compat.validation.missing,
15027
- typeErrors: compat.validation.typeErrors
15028
- });
15029
- await onInterceptedToolCall(reroutedWrite.toolCall);
15030
- return {
15031
- intercepted: true,
15032
- skipConverter: true
15033
- };
15034
- }
15035
15014
  if (schemaValidationFailureMode === "pass_through" && shouldTerminateOnSchemaValidation(normalizedToolCall, compat.validation)) {
15036
15015
  return {
15037
15016
  intercepted: false,
@@ -15341,36 +15320,6 @@ function shouldUsePassThroughForEditSchema(event) {
15341
15320
  const normalizedName = rawName.endsWith("ToolCall") ? rawName.slice(0, -"ToolCall".length) : rawName;
15342
15321
  return normalizedName.toLowerCase() === "edit";
15343
15322
  }
15344
- function tryRerouteEditToWrite(toolCall, normalizedArgs, allowedToolNames, toolSchemaMap) {
15345
- if (toolCall.function.name.toLowerCase() !== "edit") {
15346
- return null;
15347
- }
15348
- if (!allowedToolNames.has("write") || !toolSchemaMap.has("write")) {
15349
- return null;
15350
- }
15351
- const path2 = typeof normalizedArgs.path === "string" && normalizedArgs.path.length > 0 ? normalizedArgs.path : null;
15352
- if (!path2) {
15353
- return null;
15354
- }
15355
- const content = typeof normalizedArgs.new_string === "string" ? normalizedArgs.new_string : typeof normalizedArgs.content === "string" ? normalizedArgs.content : null;
15356
- if (content === null) {
15357
- return null;
15358
- }
15359
- const oldString = normalizedArgs.old_string;
15360
- if (typeof oldString === "string" && oldString.length > 0) {
15361
- return null;
15362
- }
15363
- return {
15364
- path: path2,
15365
- toolCall: {
15366
- ...toolCall,
15367
- function: {
15368
- name: "write",
15369
- arguments: JSON.stringify({ path: path2, content })
15370
- }
15371
- }
15372
- };
15373
- }
15374
15323
  function isRecord4(value) {
15375
15324
  return typeof value === "object" && value !== null && !Array.isArray(value);
15376
15325
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rama_nigg/open-cursor",
3
- "version": "2.4.1",
3
+ "version": "2.4.3",
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",
@@ -11,7 +11,7 @@
11
11
  "test": "bun test",
12
12
  "test:unit": "bun test tests/unit",
13
13
  "test:integration": "bun test tests/integration",
14
- "test:ci:unit": "bun test tests/tools/defaults.test.ts tests/tools/executor-chain.test.ts tests/tools/sdk-executor.test.ts tests/tools/mcp-executor.test.ts tests/tools/skills.test.ts tests/tools/registry.test.ts tests/unit/cli/model-discovery.test.ts tests/unit/proxy/prompt-builder.test.ts tests/unit/proxy/tool-loop.test.ts tests/unit/provider-boundary.test.ts tests/unit/provider-runtime-interception.test.ts tests/unit/provider-tool-schema-compat.test.ts tests/unit/provider-tool-loop-guard.test.ts tests/unit/plugin.test.ts tests/unit/plugin-tools-hook.test.ts tests/unit/plugin-tool-resolution.test.ts tests/unit/plugin-config.test.ts tests/unit/plugin-stream-extraction.test.ts tests/unit/auth.test.ts tests/unit/streaming/line-buffer.test.ts tests/unit/streaming/parser.test.ts tests/unit/streaming/types.test.ts tests/unit/streaming/delta-tracker.test.ts tests/unit/streaming/openai-sse.test.ts tests/unit/streaming/ai-sdk-parts.test.ts tests/competitive/edge.test.ts",
14
+ "test:ci:unit": "bun test tests/tools/defaults.test.ts tests/tools/executor-chain.test.ts tests/tools/sdk-executor.test.ts tests/tools/mcp-executor.test.ts tests/tools/skills.test.ts tests/tools/registry.test.ts tests/unit/cli/opencode-cursor.test.ts tests/unit/cli/model-discovery.test.ts tests/unit/proxy/prompt-builder.test.ts tests/unit/proxy/tool-loop.test.ts tests/unit/provider-boundary.test.ts tests/unit/provider-runtime-interception.test.ts tests/unit/provider-tool-schema-compat.test.ts tests/unit/provider-tool-loop-guard.test.ts tests/unit/plugin.test.ts tests/unit/plugin-tools-hook.test.ts tests/unit/plugin-tool-resolution.test.ts tests/unit/plugin-config.test.ts tests/unit/plugin-stream-extraction.test.ts tests/unit/auth.test.ts tests/unit/streaming/line-buffer.test.ts tests/unit/streaming/parser.test.ts tests/unit/streaming/types.test.ts tests/unit/streaming/delta-tracker.test.ts tests/unit/streaming/openai-sse.test.ts tests/unit/streaming/ai-sdk-parts.test.ts tests/competitive/edge.test.ts",
15
15
  "test:ci:integration": "bun test tests/integration/comprehensive.test.ts tests/integration/tools-router.integration.test.ts tests/integration/stream-router.integration.test.ts tests/integration/opencode-loop.integration.test.ts",
16
16
  "check:pricing": "bun run scripts/check-cursor-pricing-coverage.ts",
17
17
  "check:pricing:fixture": "bun run scripts/check-cursor-pricing-coverage.ts --models-file tests/fixtures/cursor-pricing-models.txt --skip-doc-fetch",
@@ -6,6 +6,7 @@ import {
6
6
  existsSync,
7
7
  lstatSync,
8
8
  mkdirSync,
9
+ realpathSync,
9
10
  readFileSync,
10
11
  rmSync,
11
12
  symlinkSync,
@@ -1035,6 +1036,26 @@ function main() {
1035
1036
  }
1036
1037
  }
1037
1038
 
1038
- if (process.env.NODE_ENV !== "test" && fileURLToPath(import.meta.url) === resolve(process.argv[1] || "")) {
1039
+ function resolveEntrypointArg(argvPath: string | undefined): string {
1040
+ if (!argvPath) return "";
1041
+ return resolve(argvPath);
1042
+ }
1043
+
1044
+ function toRealPath(path: string): string {
1045
+ try {
1046
+ return realpathSync(path);
1047
+ } catch {
1048
+ return path;
1049
+ }
1050
+ }
1051
+
1052
+ export function isCliEntrypoint(metaUrl: string, argvPath: string | undefined): boolean {
1053
+ const currentPath = fileURLToPath(metaUrl);
1054
+ const argvResolved = resolveEntrypointArg(argvPath);
1055
+ if (!argvResolved) return false;
1056
+ return currentPath === argvResolved || toRealPath(currentPath) === toRealPath(argvResolved);
1057
+ }
1058
+
1059
+ if (process.env.NODE_ENV !== "test" && isCliEntrypoint(import.meta.url, process.argv[1])) {
1039
1060
  main();
1040
1061
  }
@@ -190,20 +190,7 @@ export async function handleToolLoopEventLegacy(
190
190
  return { intercepted: false, skipConverter: true, terminate: validationTermination };
191
191
  }
192
192
 
193
- const reroutedWrite = tryRerouteEditToWrite(
194
- normalizedToolCall,
195
- compat.normalizedArgs,
196
- allowedToolNames,
197
- toolSchemaMap,
198
- );
199
- if (reroutedWrite) {
200
- log.debug("Rerouting malformed edit call to write (legacy)", {
201
- path: reroutedWrite.path,
202
- missing: compat.validation.missing,
203
- typeErrors: compat.validation.typeErrors,
204
- });
205
- normalizedToolCall = reroutedWrite.toolCall;
206
- } else if (shouldEmitNonFatalSchemaValidationHint(normalizedToolCall, compat.validation)) {
193
+ if (shouldEmitNonFatalSchemaValidationHint(normalizedToolCall, compat.validation)) {
207
194
  const hintChunk = createNonFatalSchemaValidationHintChunk(
208
195
  responseMeta,
209
196
  normalizedToolCall,
@@ -386,24 +373,6 @@ export async function handleToolLoopEventV1(
386
373
  }
387
374
  return { intercepted: false, skipConverter: true, terminate: termination };
388
375
  }
389
- const reroutedWrite = tryRerouteEditToWrite(
390
- normalizedToolCall,
391
- compat.normalizedArgs,
392
- allowedToolNames,
393
- toolSchemaMap,
394
- );
395
- if (reroutedWrite) {
396
- log.debug("Rerouting malformed edit call to write", {
397
- path: reroutedWrite.path,
398
- missing: compat.validation.missing,
399
- typeErrors: compat.validation.typeErrors,
400
- });
401
- await onInterceptedToolCall(reroutedWrite.toolCall);
402
- return {
403
- intercepted: true,
404
- skipConverter: true,
405
- };
406
- }
407
376
  if (
408
377
  schemaValidationFailureMode === "pass_through"
409
378
  && shouldTerminateOnSchemaValidation(normalizedToolCall, compat.validation)
@@ -809,53 +778,6 @@ function shouldUsePassThroughForEditSchema(event: StreamJsonToolCallEvent): bool
809
778
  return normalizedName.toLowerCase() === "edit";
810
779
  }
811
780
 
812
- function tryRerouteEditToWrite(
813
- toolCall: OpenAiToolCall,
814
- normalizedArgs: Record<string, unknown>,
815
- allowedToolNames: Set<string>,
816
- toolSchemaMap: Map<string, unknown>,
817
- ): { path: string; toolCall: OpenAiToolCall } | null {
818
- if (toolCall.function.name.toLowerCase() !== "edit") {
819
- return null;
820
- }
821
- if (!allowedToolNames.has("write") || !toolSchemaMap.has("write")) {
822
- return null;
823
- }
824
-
825
- const path = typeof normalizedArgs.path === "string" && normalizedArgs.path.length > 0
826
- ? normalizedArgs.path
827
- : null;
828
- if (!path) {
829
- return null;
830
- }
831
-
832
- const content =
833
- typeof normalizedArgs.new_string === "string"
834
- ? normalizedArgs.new_string
835
- : typeof normalizedArgs.content === "string"
836
- ? normalizedArgs.content
837
- : null;
838
- if (content === null) {
839
- return null;
840
- }
841
-
842
- const oldString = normalizedArgs.old_string;
843
- if (typeof oldString === "string" && oldString.length > 0) {
844
- return null;
845
- }
846
-
847
- return {
848
- path,
849
- toolCall: {
850
- ...toolCall,
851
- function: {
852
- name: "write",
853
- arguments: JSON.stringify({ path, content }),
854
- },
855
- },
856
- };
857
- }
858
-
859
781
  function isRecord(value: unknown): value is Record<string, unknown> {
860
782
  return typeof value === "object" && value !== null && !Array.isArray(value);
861
783
  }
@@ -261,8 +261,8 @@ function normalizeToolSpecificArgs(toolName: string, args: JsonRecord): JsonReco
261
261
  if (!hasStringNew && typeof content === "string") {
262
262
  repaired.new_string = content;
263
263
  }
264
- if (typeof repaired.new_string === "string" && !hasStringOld) {
265
- repaired.old_string = "";
264
+ if (hasStringOld && repaired.old_string === "") {
265
+ delete repaired.old_string;
266
266
  }
267
267
 
268
268
  return repaired;