@tduyng/pi-cursor 0.0.2 → 0.0.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.
Files changed (2) hide show
  1. package/README.md +64 -51
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,25 +1,21 @@
1
1
  # pi-cursor
2
2
 
3
- Cursor models in Pi through the official Cursor SDK. Pi keeps its own system prompt, tools, approvals, compaction and session tree. Cursor is only the authenticated model transport.
3
+ Cursor models in pi, through the official Cursor SDK. Pi keeps the prompt, the tools, the approvals, the compaction, and the session tree.
4
4
 
5
- No Cursor CLI is installed or called. Login is the SDK browser flow, which mints a stored Cursor API key under `~/.cursor/sdk/auth.json`.
5
+ ## What it costs
6
6
 
7
- The provider id is `cursor`, and model ids are Cursor's own ids. `/model cursor/gpt-5.5` and `/model cursor/claude-opus-4-8` work as written.
7
+ No tools, no prompt block, no schema. It is a model provider, so it adds nothing to the context and nothing to the cold start.
8
+
9
+ What it saves on the wire is the replay. A normal turn sends only the new user message, a tool round sends nothing, and a restarted pi process resumes the same Cursor agent instead of replaying the conversation.
8
10
 
9
11
  ## Requirements
10
12
 
11
13
  - Pi 1.4 or newer.
12
14
  - Node 24 or newer.
13
15
  - A Cursor account.
14
- - The extension dependency `@cursor/sdk` 1.0.40, installed by the workspace.
15
-
16
- ## Install
17
-
18
- ```sh
19
- pi install /path/to/extensions/pi-cursor
20
- ```
16
+ - `@cursor/sdk` 1.0.40, installed by the workspace.
21
17
 
22
- In this repository the workspace already registers the extension in the root `package.json`.
18
+ No Cursor CLI is installed or called. Login is the SDK browser flow, which mints a stored Cursor key under `~/.cursor/sdk/auth.json`.
23
19
 
24
20
  ## Login
25
21
 
@@ -27,11 +23,11 @@ In this repository the workspace already registers the extension in the root `pa
27
23
  /cursor login
28
24
  ```
29
25
 
30
- The SDK opens the Cursor login page and mints a key when the browser flow finishes. If the browser does not open, the command prints the URL. `/cursor status` shows the account and `/cursor logout` removes the stored key.
26
+ The SDK opens the Cursor login page and mints a key when the flow finishes. If the browser does not open, the command prints the URL. `/cursor status` shows the account and `/cursor logout` removes the stored key.
31
27
 
32
- `CURSOR_API_KEY` overrides the stored login. The key is read by the SDK, not copied into Pi's `auth.json`.
28
+ `CURSOR_API_KEY` overrides the stored login. The key is read by the SDK and not copied into pi's `auth.json`.
33
29
 
34
- Cursor bills SDK traffic under its own terms. This extension cannot tell you whether a run is plan-included, so check the Cursor dashboard for the account's SDK usage.
30
+ Cursor bills SDK traffic under its own terms, and this extension cannot tell you whether a run is plan-included. Check the Cursor dashboard for the account's SDK usage.
35
31
 
36
32
  ## Use
37
33
 
@@ -39,62 +35,79 @@ Cursor bills SDK traffic under its own terms. This extension cannot tell you whe
39
35
  /model cursor/gpt-5.5
40
36
  ```
41
37
 
42
- The model list comes from `Cursor.models.list()`, cached after the last successful read in `~/.pi/agent/pi-cursor-models.json` (0600, keyed by the credential). Startup registers the cache with no network call, the session start refresh replaces it, and a small built-in list is the fallback when there is no cache yet. A model that offers several context windows is registered once per window: the plain id uses the smallest one, `cursor/gpt-5.5@1m` asks for 1M. Cursor bills the larger windows as Max Mode, so the small default is the cheap one. `/cursor models` prints them.
38
+ The provider id is `cursor` and model ids are Cursor's own. The list comes from `Cursor.models.list()`, cached after the last successful read in `~/.pi/agent/pi-cursor-models.json` at mode 0600 and keyed by the credential. Startup registers the cache with no network call, session start refreshes it, and a small built-in list is the fallback.
43
39
 
44
- `/cursor fast on` adds Cursor's `fast` model parameter to every model that exposes it. It is a billing choice, so it stays off until you ask for it. `/cursor status` shows the current setting.
40
+ A model that offers several context windows is registered once per window: the plain id uses the smallest one, and `cursor/gpt-5.5@1m` asks for 1M. Cursor bills the larger windows as Max Mode, so the small default is the cheap one. `/cursor models` prints them.
41
+
42
+ `/cursor fast on` adds Cursor's `fast` parameter to every model that exposes it. It is a billing choice, so it stays off until you ask. `/cursor status` shows the current setting.
45
43
 
46
44
  ## How it works
47
45
 
48
- | Pi | Cursor SDK |
49
- | ------------------------- | ------------------------------------------------------------------------------------ |
50
- | Pi system prompt | `AgentOptions.systemPrompt`, replaces the Cursor harness prompt |
51
- | Pi tools | `LocalAgentOptions.customTools`, one in-process callback per Pi tool |
52
- | Cursor built-ins | `AgentOptions.tools: ['mcp']`, so only Pi's custom tools exist |
53
- | Cursor rules, skills, MCP | `local.settingSources: []` |
54
- | Pi tool execution | the custom tool callback parks, Pi runs the tool, the next provider call resolves it |
46
+ | Pi | Cursor SDK |
47
+ | --- | --- |
48
+ | Pi system prompt | `AgentOptions.systemPrompt`, replacing the Cursor harness prompt |
49
+ | Pi tools | `LocalAgentOptions.customTools`, one in-process callback per tool |
50
+ | Cursor built-ins | `AgentOptions.tools: ['mcp']`, so only pi's custom tools exist |
51
+ | Cursor rules, skills, MCP | `local.settingSources: []` |
52
+ | Pi tool execution | The callback parks, pi runs the tool, the next provider call resolves it |
53
+
54
+ A tool call does not end the Cursor run. The callback waits, pi executes the named tool through its normal pipeline, and the next `streamSimple` call resolves the callback with the result. The same run continues, so the model sees the result in the same conversation.
55
+
56
+ A message you steer in while a tool runs is delivered with `Run.steer`, so the model reads it before its next step. Images attached to such a message become a one-line note, because steering carries text only.
57
+
58
+ One agent runs per pi session. The agent is replaced only when the prompt, tool set, or working directory changes, or when the pi history diverges, and that replacement replays the conversation once as a single message.
59
+
60
+ A restarted pi process resumes the same agent instead of replaying. At the end of every clean turn the extension records the agent id with the working folder, prompt and tool hashes, the pi message count, and its own hash of that prefix, in `~/.pi/agent/pi-cursor-agents.json`. The next process calls `Agent.resume` when all of those still match and the pending turn is a single new user message. A stale id, a diverged fork, or a turn killed mid tool round falls back to the replay. The ledger keeps the last 20 sessions, and `/cursor clear`, `/cursor login`, and `/cursor logout` delete it, so those commands really do start from a fresh agent.
55
61
 
56
- A tool call does not end the Cursor run. The callback waits, Pi executes the named tool through its normal pipeline, and the next `streamSimple` call resolves the callback with the result. The same Cursor run continues, so the model sees the tool result in the same conversation. A message you steer in while that tool is running is delivered with `Run.steer`, so the model reads it before its next step; images attached to such a message become a one-line note because steering carries text only.
62
+ There is no HTTP MCP server, no Hono server, and no tool-name rewriting: the SDK invokes the callback directly.
57
63
 
58
- One Cursor agent runs per Pi session. A normal turn sends only the new user message. A tool round resolves parked callbacks and sends nothing. The agent is only replaced when Pi's prompt, tool set or working directory changes, or when the Pi history diverges. That replacement replays the existing Pi conversation once as a single message.
64
+ ## What the wire costs
59
65
 
60
- A restarted Pi process resumes the same Cursor agent instead of replaying. At the end of every clean turn the extension records the agent id with the working folder, prompt and tool hashes, the Pi message count and the extension's hash of that prefix, in `~/.pi/agent/pi-cursor-agents.json`. The next process calls `Agent.resume` when all of those still match and the pending turn is a single new user message. A stale id, a fork that diverged, or a turn that was killed mid tool round all fall back to the replay, which is the pre-resume behavior. The ledger keeps the last 20 sessions. `/cursor clear`, `/cursor login` and `/cursor logout` delete it, so those commands really do start from a fresh agent.
66
+ Measured on the account this extension was built on, with gpt-5.5 and auto-smart, thinking off:
61
67
 
62
- There is no HTTP MCP server, no Hono server and no tool-name rewriting. Cursor's SDK invokes the callback directly.
68
+ | Call | Input tokens | Wall time |
69
+ | --- | --- | --- |
70
+ | First call of an agent | 11.9k fresh plus 2.6k cached | 4.8 to 5.5s |
71
+ | Plain follow-up turn | 12.9k fresh plus 12.7k cached | 2.2s |
72
+ | Call after a tool round | 36.9k fresh plus 36.0k cached | 4.4 to 13s |
63
73
 
64
- ## Token and cache behavior
74
+ The tool-round number is Cursor's, not the tool result. The SDK re-prefills its own context around the custom tool callback, so one tool call costs about three plain calls. A turn that ends in a tool call is the slow turn, and there is no pi-side switch for it. The same 32k fresh appears with an empty working directory, so it is not workspace scanning. Fewer, wider tool calls per turn is the lever that exists.
65
75
 
66
- Cursor's backend owns its own conversation and cache. Pi does not replay a linear conversation on every turn, it does not run a second agent for tool rounds, and a restart resumes the agent rather than replaying. The Pi system prompt is stable for the lifetime of an agent, and the tool list is stable too. A divergence is the only case that pays a replay.
76
+ Thinking levels map to Cursor model parameters: `thinking` and `effort` for Claude models, `reasoning` for GPT, `effort` for Grok, from the live catalog.
67
77
 
68
- Thinking levels map to Cursor model parameters. For Claude models the extension sets both `thinking` and `effort`. For GPT models it sets `reasoning`. For Grok it sets `effort`. The mapping comes from the live model catalog.
78
+ ## Limits
69
79
 
70
- What the wire actually costs, measured on the account this extension was built on (gpt-5.5 and auto-smart, thinking off):
80
+ - Cursor owns the agent loop and its context management, so pi's compaction does not reach inside a live agent.
71
81
 
72
- | Call | Input tokens | Wall time |
73
- | ----------------------- | -------------------------- | --------- |
74
- | first call of an agent | 11.9k fresh + 2.6k cached | 4.8-5.5 s |
75
- | plain follow-up turn | 12.9k fresh + 12.7k cached | 2.2 s |
76
- | call after a tool round | 36.9k fresh + 36.0k cached | 4.4-13 s |
82
+ - `AgentOptions.systemPrompt` is server-gated. A rejected prompt comes back as a failed run about 20 seconds in, not from `Agent.create`, so the extension retries that turn with the prompt prepended to the first message.
77
83
 
78
- The tool-round number is Cursor's, not the tool result: the SDK re-prefills its own context around the custom tool callback, so one tool call costs about three plain calls. A turn that ends in a tool call is the slow turn, and there is no Pi-side switch for it. The same 32k fresh appears when the working directory is empty, so it is not workspace scanning. Fewer, wider tool calls per turn is the lever that exists.
84
+ - The rejection is recorded as `noSystemPrompt` in `~/.pi/agent/pi-cursor.json`, and every later agent skips the doomed attempt. Clear it with `/cursor login` or by editing the file, and `/cursor status` shows which path is in use. The fallback works but spends more tokens, because the Cursor harness prompt remains.
79
85
 
80
- ## Limitations
86
+ - A failed run reaches pi as an error message, so an empty answer means a broken transport rather than a silent backend rejection.
81
87
 
82
- - Cursor owns the agent loop and its context management. Pi's compaction does not reach inside a live Cursor agent.
83
- - `AgentOptions.systemPrompt` is server-gated. A rejected prompt comes back as a failed run about 20 seconds in, not from `Agent.create`, so the extension retries that turn with the prompt prepended to the first message. The rejection is recorded as `noSystemPrompt` in `~/.pi/agent/pi-cursor.json` and every later agent skips the doomed attempt. Clear that flag with `/cursor login`, or edit the file. `/cursor status` shows which path is in use. The fallback works but spends more tokens because Cursor's harness prompt remains.
84
- - A failed Cursor run reaches Pi as an error message, so an empty answer now means a broken transport, not a silent backend rejection.
85
- - Usage tokens come from Cursor's `turn-ended` events, plus the run's own total when it ends. Pi records each message's share of the run, so the numbers add up across a tool round instead of keeping only the last step. The message that ends in a tool call shows zero because that step has not ended server-side yet, and the next message carries both steps. Pi shows a zero money cost because Cursor bills outside Pi.
86
- - Images ride with the message that carries them. A replay replaces every earlier image with an `[image: mime]` placeholder and keeps only the pending message's images, so reattach one to ask about it again after a restart.
87
- - A model id that Cursor no longer serves fails at `send`, not at model selection.
88
- - A long Pi tool run is held open by Cursor local runtime. The SDK does not document a timeout for custom tools.
89
- - The Cursor SDK is a 25 MB dependency with optional platform packages.
88
+ - Usage tokens come from Cursor's `turn-ended` events plus the run's own total, and pi records each message's share, so the numbers add across a tool round. A message that ends in a tool call shows zero, because that step has not ended server side, and the next message carries both. Pi shows zero money cost because Cursor bills outside pi.
90
89
 
91
- ## Configuration
90
+ - Images ride with the message that carries them. A replay replaces earlier images with an `[image: mime]` placeholder and keeps only the pending message's images, so reattach one to ask about it again after a restart.
92
91
 
93
- | Variable | Meaning |
94
- | ---------------- | ----------------------------------------------- |
95
- | `CURSOR_API_KEY` | Cursor API key. Overrides the stored SDK login. |
92
+ - A model id Cursor no longer serves fails at `send`, not at selection.
93
+
94
+ - A long pi tool run is held open by the Cursor local runtime, and the SDK documents no timeout for custom tools.
95
+
96
+ - The SDK is a 25 MB dependency with optional platform packages.
97
+
98
+ ## Configure
99
+
100
+ `CURSOR_API_KEY` overrides the stored login.
101
+
102
+ `~/.pi/agent/pi-cursor.json` holds the two preferences: `fast`, from `/cursor fast`, and `noSystemPrompt`, once Cursor has refused pi's prompt for this account.
103
+
104
+ ## Install
105
+
106
+ ```sh
107
+ pi install npm:@tduyng/pi-cursor
108
+ ```
96
109
 
97
- `~/.pi/agent/pi-cursor.json` holds the two preferences: `fast` from `/cursor fast`, and `noSystemPrompt` once Cursor has refused the Pi prompt for this account.
110
+ Local checkout: `pi install /path/to/dotfiles/pi/agent/extensions/pi-cursor`
98
111
 
99
112
  ## Tests
100
113
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tduyng/pi-cursor",
3
- "version": "0.0.2",
4
- "description": "Use Cursor models in Pi through the official Cursor SDK, with Pi's own prompt and tools.",
3
+ "version": "0.0.3",
4
+ "description": "Cursor models in Pi through the official Cursor SDK: one warm agent per session, Pi's own prompt and tools, resumed instead of replayed.",
5
5
  "keywords": [
6
6
  "pi",
7
7
  "pi-package",