@rama_nigg/open-cursor 2.3.4 → 2.3.5

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/README.md CHANGED
@@ -7,11 +7,6 @@
7
7
 
8
8
  No prompt limits. No broken streams. Full thinking + tool support in OpenCode. Your Cursor subscription, properly integrated.
9
9
 
10
- ## Prerequisites
11
-
12
- Required: [OpenCode](https://opencode.ai/) + [cursor-agent](https://cursor.com/) (`curl -fsSL https://cursor.com/install | bash && cursor-agent login`)
13
- Optional: [Bun](https://bun.sh/) (Options B-F), [Go 1.21+](https://go.dev/) (Option D)
14
-
15
10
  ## Installation
16
11
 
17
12
  ### Option A — One-line installer
@@ -20,7 +15,8 @@ Optional: [Bun](https://bun.sh/) (Options B-F), [Go 1.21+](https://go.dev/) (Opt
20
15
  curl -fsSL https://raw.githubusercontent.com/Nomadcxx/opencode-cursor/main/install.sh | bash
21
16
  ```
22
17
 
23
- ### Option B — Add to opencode.json
18
+ <details>
19
+ <summary><b>Option B</b> — Add to opencode.json</summary>
24
20
 
25
21
  Add to `~/.config/opencode/opencode.json`:
26
22
 
@@ -72,8 +68,10 @@ Add to `~/.config/opencode/opencode.json`:
72
68
  ```
73
69
 
74
70
  > Update models anytime: `cursor-agent models`
71
+ </details>
75
72
 
76
- ### Option C — npm global + CLI
73
+ <details>
74
+ <summary><b>Option C</b> — npm global + CLI</summary>
77
75
 
78
76
  ```bash
79
77
  npm install -g @rama_nigg/open-cursor
@@ -81,22 +79,28 @@ open-cursor install
81
79
  ```
82
80
 
83
81
  Upgrade: `npm update -g @rama_nigg/open-cursor`
82
+ </details>
84
83
 
85
- ### Option D — Go TUI installer
84
+ <details>
85
+ <summary><b>Option D</b> — Go TUI installer</summary>
86
86
 
87
87
  ```bash
88
88
  git clone https://github.com/Nomadcxx/opencode-cursor.git
89
89
  cd opencode-cursor
90
90
  go build -o ./installer ./cmd/installer && ./installer
91
91
  ```
92
+ </details>
92
93
 
93
- ### Option E — LLM paste
94
+ <details>
95
+ <summary><b>Option E</b> — LLM paste</summary>
94
96
 
95
97
  ```
96
98
  Install open-cursor for OpenCode: edit ~/.config/opencode/opencode.json, add "@rama_nigg/open-cursor@latest" to "plugin", add a "cursor-acp" provider with npm "@ai-sdk/openai-compatible" and models from `cursor-agent models` prefixed with "cursor-acp/". Auth: `cursor-agent login`. Verify: `opencode models | grep cursor-acp`.
97
99
  ```
100
+ </details>
98
101
 
99
- ### Option F — Manual (from source)
102
+ <details>
103
+ <summary><b>Option F</b> — Manual (from source)</summary>
100
104
 
101
105
  ```bash
102
106
  git clone https://github.com/Nomadcxx/opencode-cursor.git && cd opencode-cursor
@@ -106,6 +110,7 @@ ln -sf $(pwd)/dist/plugin-entry.js ~/.config/opencode/plugin/cursor-acp.js
106
110
  ```
107
111
 
108
112
  Add `"cursor-acp"` to the `plugin` array and reuse the provider block from Option B.
113
+ </details>
109
114
 
110
115
  ## Authentication
111
116
 
@@ -170,6 +175,23 @@ Default mode: `CURSOR_ACP_TOOL_LOOP_MODE=opencode`. Legacy `proxy-exec` still av
170
175
 
171
176
  Debug logging: `CURSOR_ACP_LOG_LEVEL=debug opencode run "your prompt" --model cursor-acp/auto`
172
177
 
178
+ ## Roadmap
179
+
180
+ ```mermaid
181
+ flowchart LR
182
+ P1[/Stabilise/] --> P2[/MCP Server/] --> P3[/Simplify/] --> P4[/ACP + MCP/]
183
+
184
+ style P1 fill:#264653,stroke:#1d3557,color:#fff
185
+ style P2 fill:#264653,stroke:#1d3557,color:#fff
186
+ style P3 fill:#495057,stroke:#343a40,color:#adb5bd
187
+ style P4 fill:#495057,stroke:#343a40,color:#adb5bd
188
+ ```
189
+
190
+ [X] **Stabilise** — Clean up dead code, fix test isolation
191
+ [ ] **MCP Server** — Expose OpenCode tools via stdio transport
192
+ [ ] **Simplify** — Rip out serialisation layers
193
+ [ ] **ACP + MCP** — Structured protocols end-to-end
194
+
173
195
  ## License
174
196
 
175
197
  BSD-3-Clause
package/dist/index.js CHANGED
@@ -17408,6 +17408,7 @@ function parseToolLoopMaxRepeat(value) {
17408
17408
  return { value: Math.floor(parsed), valid: true };
17409
17409
  }
17410
17410
  function createToolLoopGuard(messages, maxRepeat) {
17411
+ const coarseMaxRepeat = maxRepeat * COARSE_LIMIT_MULTIPLIER;
17411
17412
  const {
17412
17413
  byCallId,
17413
17414
  latest,
@@ -17447,13 +17448,13 @@ function createToolLoopGuard(messages, maxRepeat) {
17447
17448
  }
17448
17449
  const strictFingerprint = `${toolCall.function.name}|${argShape}|${errorClass}`;
17449
17450
  const coarseFingerprint = `${toolCall.function.name}|${errorClass}`;
17450
- return evaluateWithFingerprints(errorClass, strictFingerprint, coarseFingerprint, counts, coarseCounts, maxRepeat);
17451
+ return evaluateWithFingerprints(errorClass, strictFingerprint, coarseFingerprint, counts, coarseCounts, maxRepeat, coarseMaxRepeat);
17451
17452
  },
17452
17453
  evaluateValidation(toolCall, validationSignature) {
17453
17454
  const normalizedSignature = normalizeValidationSignature(validationSignature);
17454
17455
  const strictFingerprint = `${toolCall.function.name}|schema:${normalizedSignature}|validation`;
17455
17456
  const coarseFingerprint = `${toolCall.function.name}|validation`;
17456
- return evaluateWithFingerprints("validation", strictFingerprint, coarseFingerprint, validationCounts, validationCoarseCounts, maxRepeat);
17457
+ return evaluateWithFingerprints("validation", strictFingerprint, coarseFingerprint, validationCounts, validationCoarseCounts, maxRepeat, coarseMaxRepeat);
17457
17458
  },
17458
17459
  resetFingerprint(fingerprint) {
17459
17460
  counts.delete(fingerprint);
@@ -17684,7 +17685,7 @@ function normalizeValidationSignature(signature) {
17684
17685
  const normalized = signature.trim().toLowerCase();
17685
17686
  return normalized.length > 0 ? normalized : "invalid";
17686
17687
  }
17687
- function evaluateWithFingerprints(errorClass, strictFingerprint, coarseFingerprint, strictCounts, coarseCounts, maxRepeat) {
17688
+ function evaluateWithFingerprints(errorClass, strictFingerprint, coarseFingerprint, strictCounts, coarseCounts, maxRepeat, coarseMaxRepeat) {
17688
17689
  if (errorClass === "success") {
17689
17690
  return {
17690
17691
  fingerprint: strictFingerprint,
@@ -17700,12 +17701,12 @@ function evaluateWithFingerprints(errorClass, strictFingerprint, coarseFingerpri
17700
17701
  const coarseRepeatCount = (coarseCounts.get(coarseFingerprint) ?? 0) + 1;
17701
17702
  coarseCounts.set(coarseFingerprint, coarseRepeatCount);
17702
17703
  const strictTriggered = strictRepeatCount > maxRepeat;
17703
- const coarseTriggered = coarseRepeatCount > maxRepeat;
17704
+ const coarseTriggered = coarseRepeatCount > coarseMaxRepeat;
17704
17705
  const preferCoarseFingerprint = coarseTriggered && !strictTriggered;
17705
17706
  return {
17706
17707
  fingerprint: preferCoarseFingerprint ? coarseFingerprint : strictFingerprint,
17707
17708
  repeatCount: preferCoarseFingerprint ? coarseRepeatCount : strictRepeatCount,
17708
- maxRepeat,
17709
+ maxRepeat: preferCoarseFingerprint ? coarseMaxRepeat : maxRepeat,
17709
17710
  errorClass,
17710
17711
  triggered: strictTriggered || coarseTriggered,
17711
17712
  tracked: true
@@ -17790,7 +17791,7 @@ function containsAny(text, patterns) {
17790
17791
  function isRecord4(value) {
17791
17792
  return typeof value === "object" && value !== null && !Array.isArray(value);
17792
17793
  }
17793
- var UNKNOWN_AS_SUCCESS_TOOLS;
17794
+ var UNKNOWN_AS_SUCCESS_TOOLS, COARSE_LIMIT_MULTIPLIER = 3;
17794
17795
  var init_tool_loop_guard = __esm(() => {
17795
17796
  UNKNOWN_AS_SUCCESS_TOOLS = new Set([
17796
17797
  "bash",
@@ -17408,6 +17408,7 @@ function parseToolLoopMaxRepeat(value) {
17408
17408
  return { value: Math.floor(parsed), valid: true };
17409
17409
  }
17410
17410
  function createToolLoopGuard(messages, maxRepeat) {
17411
+ const coarseMaxRepeat = maxRepeat * COARSE_LIMIT_MULTIPLIER;
17411
17412
  const {
17412
17413
  byCallId,
17413
17414
  latest,
@@ -17447,13 +17448,13 @@ function createToolLoopGuard(messages, maxRepeat) {
17447
17448
  }
17448
17449
  const strictFingerprint = `${toolCall.function.name}|${argShape}|${errorClass}`;
17449
17450
  const coarseFingerprint = `${toolCall.function.name}|${errorClass}`;
17450
- return evaluateWithFingerprints(errorClass, strictFingerprint, coarseFingerprint, counts, coarseCounts, maxRepeat);
17451
+ return evaluateWithFingerprints(errorClass, strictFingerprint, coarseFingerprint, counts, coarseCounts, maxRepeat, coarseMaxRepeat);
17451
17452
  },
17452
17453
  evaluateValidation(toolCall, validationSignature) {
17453
17454
  const normalizedSignature = normalizeValidationSignature(validationSignature);
17454
17455
  const strictFingerprint = `${toolCall.function.name}|schema:${normalizedSignature}|validation`;
17455
17456
  const coarseFingerprint = `${toolCall.function.name}|validation`;
17456
- return evaluateWithFingerprints("validation", strictFingerprint, coarseFingerprint, validationCounts, validationCoarseCounts, maxRepeat);
17457
+ return evaluateWithFingerprints("validation", strictFingerprint, coarseFingerprint, validationCounts, validationCoarseCounts, maxRepeat, coarseMaxRepeat);
17457
17458
  },
17458
17459
  resetFingerprint(fingerprint) {
17459
17460
  counts.delete(fingerprint);
@@ -17684,7 +17685,7 @@ function normalizeValidationSignature(signature) {
17684
17685
  const normalized = signature.trim().toLowerCase();
17685
17686
  return normalized.length > 0 ? normalized : "invalid";
17686
17687
  }
17687
- function evaluateWithFingerprints(errorClass, strictFingerprint, coarseFingerprint, strictCounts, coarseCounts, maxRepeat) {
17688
+ function evaluateWithFingerprints(errorClass, strictFingerprint, coarseFingerprint, strictCounts, coarseCounts, maxRepeat, coarseMaxRepeat) {
17688
17689
  if (errorClass === "success") {
17689
17690
  return {
17690
17691
  fingerprint: strictFingerprint,
@@ -17700,12 +17701,12 @@ function evaluateWithFingerprints(errorClass, strictFingerprint, coarseFingerpri
17700
17701
  const coarseRepeatCount = (coarseCounts.get(coarseFingerprint) ?? 0) + 1;
17701
17702
  coarseCounts.set(coarseFingerprint, coarseRepeatCount);
17702
17703
  const strictTriggered = strictRepeatCount > maxRepeat;
17703
- const coarseTriggered = coarseRepeatCount > maxRepeat;
17704
+ const coarseTriggered = coarseRepeatCount > coarseMaxRepeat;
17704
17705
  const preferCoarseFingerprint = coarseTriggered && !strictTriggered;
17705
17706
  return {
17706
17707
  fingerprint: preferCoarseFingerprint ? coarseFingerprint : strictFingerprint,
17707
17708
  repeatCount: preferCoarseFingerprint ? coarseRepeatCount : strictRepeatCount,
17708
- maxRepeat,
17709
+ maxRepeat: preferCoarseFingerprint ? coarseMaxRepeat : maxRepeat,
17709
17710
  errorClass,
17710
17711
  triggered: strictTriggered || coarseTriggered,
17711
17712
  tracked: true
@@ -17790,7 +17791,7 @@ function containsAny(text, patterns) {
17790
17791
  function isRecord4(value) {
17791
17792
  return typeof value === "object" && value !== null && !Array.isArray(value);
17792
17793
  }
17793
- var UNKNOWN_AS_SUCCESS_TOOLS;
17794
+ var UNKNOWN_AS_SUCCESS_TOOLS, COARSE_LIMIT_MULTIPLIER = 3;
17794
17795
  var init_tool_loop_guard = __esm(() => {
17795
17796
  UNKNOWN_AS_SUCCESS_TOOLS = new Set([
17796
17797
  "bash",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rama_nigg/open-cursor",
3
- "version": "2.3.4",
3
+ "version": "2.3.5",
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",
@@ -52,10 +52,16 @@ export function parseToolLoopMaxRepeat(
52
52
  return { value: Math.floor(parsed), valid: true };
53
53
  }
54
54
 
55
+ // Coarse fingerprint (tool|errorClass without args) uses a higher multiplier
56
+ // to allow legitimate exploration across different files/targets while still
57
+ // catching spray-and-pray patterns.
58
+ const COARSE_LIMIT_MULTIPLIER = 3;
59
+
55
60
  export function createToolLoopGuard(
56
61
  messages: Array<unknown>,
57
62
  maxRepeat: number,
58
63
  ): ToolLoopGuard {
64
+ const coarseMaxRepeat = maxRepeat * COARSE_LIMIT_MULTIPLIER;
59
65
  const {
60
66
  byCallId,
61
67
  latest,
@@ -125,6 +131,7 @@ export function createToolLoopGuard(
125
131
  counts,
126
132
  coarseCounts,
127
133
  maxRepeat,
134
+ coarseMaxRepeat,
128
135
  );
129
136
  },
130
137
 
@@ -139,6 +146,7 @@ export function createToolLoopGuard(
139
146
  validationCounts,
140
147
  validationCoarseCounts,
141
148
  maxRepeat,
149
+ coarseMaxRepeat,
142
150
  );
143
151
  },
144
152
 
@@ -454,6 +462,7 @@ function evaluateWithFingerprints(
454
462
  strictCounts: Map<string, number>,
455
463
  coarseCounts: Map<string, number>,
456
464
  maxRepeat: number,
465
+ coarseMaxRepeat: number,
457
466
  ): ToolLoopGuardDecision {
458
467
  if (errorClass === "success") {
459
468
  return {
@@ -471,12 +480,12 @@ function evaluateWithFingerprints(
471
480
  const coarseRepeatCount = (coarseCounts.get(coarseFingerprint) ?? 0) + 1;
472
481
  coarseCounts.set(coarseFingerprint, coarseRepeatCount);
473
482
  const strictTriggered = strictRepeatCount > maxRepeat;
474
- const coarseTriggered = coarseRepeatCount > maxRepeat;
483
+ const coarseTriggered = coarseRepeatCount > coarseMaxRepeat;
475
484
  const preferCoarseFingerprint = coarseTriggered && !strictTriggered;
476
485
  return {
477
486
  fingerprint: preferCoarseFingerprint ? coarseFingerprint : strictFingerprint,
478
487
  repeatCount: preferCoarseFingerprint ? coarseRepeatCount : strictRepeatCount,
479
- maxRepeat,
488
+ maxRepeat: preferCoarseFingerprint ? coarseMaxRepeat : maxRepeat,
480
489
  errorClass,
481
490
  triggered: strictTriggered || coarseTriggered,
482
491
  tracked: true,