pi-provider-cursor-ask 0.1.0
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/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +87 -0
- package/README.zh-CN.md +87 -0
- package/UPSTREAM_CHANGELOG.md +368 -0
- package/UPSTREAM_SOURCE.md +23 -0
- package/dist/index.js +54 -0
- package/package.json +97 -0
- package/src/auth/cli-credentials.ts +275 -0
- package/src/auth/consent.ts +25 -0
- package/src/auth/index.ts +23 -0
- package/src/auth/oauth.ts +282 -0
- package/src/auth/refresh-guard.ts +93 -0
- package/src/client/bridge.ts +673 -0
- package/src/client/cursor-wire.ts +213 -0
- package/src/client/h2-unary.ts +142 -0
- package/src/client/index.ts +18 -0
- package/src/config/index.ts +69 -0
- package/src/diagnostics/diagnostics.ts +116 -0
- package/src/diagnostics/index.ts +1 -0
- package/src/extension/auth.ts +99 -0
- package/src/extension/commands.ts +163 -0
- package/src/extension/compaction-guard.ts +86 -0
- package/src/extension/debug-hooks.ts +359 -0
- package/src/extension/index.ts +8 -0
- package/src/extension/provider.ts +277 -0
- package/src/extension/quota-adapter.ts +175 -0
- package/src/extension/report-dashboard.ts +133 -0
- package/src/identity.ts +16 -0
- package/src/index.ts +186 -0
- package/src/models/ask-catalog.ts +384 -0
- package/src/models/catalog.json +1163 -0
- package/src/models/cost.ts +126 -0
- package/src/models/index.ts +6 -0
- package/src/models/limits.ts +36 -0
- package/src/models/parameterized.ts +416 -0
- package/src/models/processing.ts +313 -0
- package/src/proto/agent_pb.ts +14577 -0
- package/src/stream/bridge-session.ts +215 -0
- package/src/stream/client-transcript.ts +51 -0
- package/src/stream/config.ts +5 -0
- package/src/stream/context-normalize.ts +308 -0
- package/src/stream/context-usage.ts +168 -0
- package/src/stream/debug-log.ts +316 -0
- package/src/stream/drift.ts +122 -0
- package/src/stream/images.ts +201 -0
- package/src/stream/index.ts +68 -0
- package/src/stream/interaction-query.ts +369 -0
- package/src/stream/message-parsing.ts +402 -0
- package/src/stream/model-cache.ts +100 -0
- package/src/stream/model-discovery.ts +242 -0
- package/src/stream/model-routing.ts +100 -0
- package/src/stream/native-core.ts +2121 -0
- package/src/stream/pi-adapter.ts +414 -0
- package/src/stream/protocol.ts +63 -0
- package/src/stream/recovery.ts +494 -0
- package/src/stream/request-build.ts +668 -0
- package/src/stream/root-prompt.ts +184 -0
- package/src/stream/run-journal.ts +474 -0
- package/src/stream/run-usage.ts +107 -0
- package/src/stream/server-messages.ts +777 -0
- package/src/stream/session-state.ts +499 -0
- package/src/stream/stream-writer.ts +211 -0
- package/src/stream/thinking-filter.ts +63 -0
- package/src/stream/tool-schema.ts +185 -0
- package/src/stream/transport-errors.ts +150 -0
- package/src/stream/tuning.ts +250 -0
- package/src/stream/types.ts +330 -0
- package/src/types/enums.ts +103 -0
- package/src/types/index.ts +4 -0
- package/src/usage.ts +262 -0
- package/src/utils/cache-dir.ts +39 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/security.ts +68 -0
- package/src/utils/util.ts +43 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# pi-provider-cursor-ask
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 98e7df4: Publish the standalone Cursor Ask provider independently. It replaces `@rahularya01/pi-cursor` under the same `cursor` login, keeps tool execution in Pi, and maps only a curated subset of models: five always-thinking 1M Claude rows, Composer 2.5 / Fast, and Grok 4.6 / Fast when the live account catalog includes them. Other Cursor families are not registered. If Cursor asks for history that is no longer in the local blob store, the current generation fails instead of returning empty history; retry rebuilds from Pi.
|
|
8
|
+
|
|
9
|
+
Release entries are maintained by Changesets.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rahul Arya
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# pi-provider-cursor-ask
|
|
2
|
+
|
|
3
|
+
[简体中文](./README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
A standalone [Pi](https://github.com/badlogic/pi-mono) provider for focused advisor, adversarial-review, and single-turn question workflows through Cursor.
|
|
6
|
+
|
|
7
|
+
This is an unofficial community fork and is not affiliated with or endorsed by Cursor or the upstream project.
|
|
8
|
+
|
|
9
|
+
## Source and differences
|
|
10
|
+
|
|
11
|
+
The package is a full fork of [`@rahularya01/pi-cursor`](https://github.com/Rahularya01/pi-cursor) `v1.4.25` (`5f8e775279f5e41cdd06791a036be4c7141097c3`). It retains the upstream native Cursor OAuth, credential discovery, streaming, tool use, image input, usage, diagnostics, and model discovery capabilities.
|
|
12
|
+
|
|
13
|
+
The fork differs in these user-visible ways:
|
|
14
|
+
|
|
15
|
+
- Replaces the upstream extension under the same `cursor` provider/login identity and `cursor-native` stream API.
|
|
16
|
+
- Keeps tool execution in Pi: requests with Pi tools expose only the Cursor MCP tool family; tool-free questions disable Cursor tools. Cursor-native filesystem, shell, and subagent tools are not offered.
|
|
17
|
+
- Maps only a curated subset of Cursor models, not the full catalog: five always-thinking 1M Claude rows, Composer 2.5 / Composer 2.5 Fast, and Grok 4.6 / Grok 4.6 Fast when the live account catalog includes them. Other Cursor families are not registered.
|
|
18
|
+
- Uses readable picker names without a separate default-context row, because Cursor bills these Claude models at one rate up to 1M.
|
|
19
|
+
- Maps only advertised Pi thinking levels. Claude uses Cursor `effort`. Composer 2.5 has no effort parameter, so `off`/`max` are an explicit Max Mode switch and other levels stay unavailable. Grok keeps upstream `low`/`medium`/`high`/`xhigh` routing instead of the Claude 1M rebuild.
|
|
20
|
+
- Publishes independently as `pi-provider-cursor-ask` and is not included in `@zhcsyncer/pi-extensions`.
|
|
21
|
+
|
|
22
|
+
See [`UPSTREAM_SOURCE.md`](./UPSTREAM_SOURCE.md) for the maintained fork record.
|
|
23
|
+
|
|
24
|
+
## Models
|
|
25
|
+
|
|
26
|
+
This package maps only the models below. The rest of the Cursor catalog is omitted.
|
|
27
|
+
|
|
28
|
+
- Fable 5.1
|
|
29
|
+
- Fable 5
|
|
30
|
+
- Opus 5
|
|
31
|
+
- Opus 4.6
|
|
32
|
+
- Sonnet 5
|
|
33
|
+
- Composer 2.5 / Composer 2.5 Fast
|
|
34
|
+
- Grok 4.6 / Grok 4.6 Fast (only when the account catalog includes them)
|
|
35
|
+
|
|
36
|
+
Thinking cannot be disabled on the five Claude rows. Depending on Cursor's metadata for a Claude model, Pi may offer `low`, `medium`, `high`, `xhigh`, and `max`; unavailable levels are omitted. Composer 2.5 exposes only `off` (standard) and `max` (Max Mode). Grok exposes `low`, `medium`, `high`, and `xhigh`.
|
|
37
|
+
|
|
38
|
+
## Requirements
|
|
39
|
+
|
|
40
|
+
- Node.js 22.19 or newer.
|
|
41
|
+
- Pi 0.80 or a compatible newer release.
|
|
42
|
+
- A Cursor account entitled to use the selected model.
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pi install npm:pi-provider-cursor-ask
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Restart Pi or run `/reload`, then sign in:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
/login cursor
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The provider can also reuse supported Cursor CLI or desktop credentials. For automated environments, set `CURSOR_ACCESS_TOKEN`.
|
|
57
|
+
|
|
58
|
+
## Use
|
|
59
|
+
|
|
60
|
+
List the filtered models:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pi --list-models cursor
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Select `cursor/fable-5.1`, `cursor/fable-5`, `cursor/opus-5`, `cursor/opus-4.6`, `cursor/sonnet-5`, or, when advertised, `cursor/grok-4.6` / `cursor/grok-4.6-fast`.
|
|
67
|
+
|
|
68
|
+
Available command:
|
|
69
|
+
|
|
70
|
+
- `/cursor usage` — open a dashboard of Cursor plan usage.
|
|
71
|
+
- `/cursor doctor` — open a dashboard of sanitized provider diagnostics.
|
|
72
|
+
|
|
73
|
+
If Cursor requests history that is no longer available locally, the current generation fails with `Refusing to answer empty` instead of sending incomplete history. Retry to rebuild from Pi's conversation history.
|
|
74
|
+
|
|
75
|
+
If `@zhcsyncer/pi-meter` is also loaded, the footer follows the current Cursor model: Composer uses the Auto pool, and Claude rows use the API pool.
|
|
76
|
+
|
|
77
|
+
This package intentionally owns the `cursor` provider id as a drop-in replacement. Do not load it together with `@rahularya01/pi-cursor`; whichever extension registers last would replace the other's `cursor` catalog.
|
|
78
|
+
|
|
79
|
+
## Security
|
|
80
|
+
|
|
81
|
+
This fork retains upstream support for local Cursor CLI/desktop credential discovery and the existing Pi `cursor` credential entry. Set `PI_CURSOR_SYSTEM_CREDENTIALS=0` before starting Pi to disable local credential discovery and use `/login cursor` or `CURSOR_ACCESS_TOKEN` instead.
|
|
82
|
+
|
|
83
|
+
Extensions run with your user permissions. Review the package before installation and never commit or paste credentials into issue reports.
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
MIT. The upstream copyright and license notice are preserved in [`LICENSE`](./LICENSE).
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# pi-provider-cursor-ask
|
|
2
|
+
|
|
3
|
+
[English](./README.md)
|
|
4
|
+
|
|
5
|
+
一个独立的 [Pi](https://github.com/badlogic/pi-mono) provider,通过 Cursor 服务于聚焦的 advisor、adversarial-review 和单轮问答工作流。
|
|
6
|
+
|
|
7
|
+
这是非官方社区 fork,与 Cursor 及上游项目没有隶属关系,也未获得其官方背书。
|
|
8
|
+
|
|
9
|
+
## 来源与差异
|
|
10
|
+
|
|
11
|
+
本包整仓 fork 自 [`@rahularya01/pi-cursor`](https://github.com/Rahularya01/pi-cursor) `v1.4.25`(`5f8e775279f5e41cdd06791a036be4c7141097c3`)。保留上游原生 Cursor OAuth、凭证发现、流式响应、工具调用、图片输入、用量、诊断和模型发现能力。
|
|
12
|
+
|
|
13
|
+
本 fork 的用户可见差异如下:
|
|
14
|
+
|
|
15
|
+
- 使用与上游相同的 `cursor` provider/登录身份和 `cursor-native` stream API 直接替换旧扩展。
|
|
16
|
+
- 工具仍由 Pi 执行:有 Pi 工具的请求只开放 Cursor MCP 工具通道;无工具问答关闭 Cursor 工具。不提供 Cursor 原生文件、shell 和子代理工具。
|
|
17
|
+
- 只映射部分 Cursor 模型,不是完整目录:5 行始终开启 thinking 的 1M Claude、Composer 2.5 / Composer 2.5 Fast,以及账号实时目录里有的 Grok 4.6 / Grok 4.6 Fast。其余系列不注册。
|
|
18
|
+
- Picker 不再拆默认上下文行:Cursor 对这些 Claude 模型按同一费率计到 1M。
|
|
19
|
+
- 只映射明确提供的 Pi thinking 档位。Claude 映射 Cursor `effort`。Composer 2.5 没有 effort 参数,因此只用 `off`/`max` 显式开关 Max Mode,其余档位保持不可用。Grok 沿用上游 `low`/`medium`/`high`/`xhigh`,不做 Claude 的 1M 重建。
|
|
20
|
+
- 以 `pi-provider-cursor-ask` 独立发布到 npm,不进入 `@zhcsyncer/pi-extensions` 根 bundle。
|
|
21
|
+
|
|
22
|
+
维护中的 fork 来源记录见 [`UPSTREAM_SOURCE.md`](./UPSTREAM_SOURCE.md)。
|
|
23
|
+
|
|
24
|
+
## 模型
|
|
25
|
+
|
|
26
|
+
本包只映射下列模型,其余 Cursor 目录不会出现。
|
|
27
|
+
|
|
28
|
+
- Fable 5.1
|
|
29
|
+
- Fable 5
|
|
30
|
+
- Opus 5
|
|
31
|
+
- Opus 4.6
|
|
32
|
+
- Sonnet 5
|
|
33
|
+
- Composer 2.5 / Composer 2.5 Fast
|
|
34
|
+
- Grok 4.6 / Grok 4.6 Fast(仅当账号目录包含时)
|
|
35
|
+
|
|
36
|
+
5 行 Claude 模型的 Thinking 无法关闭。根据 Cursor 为各 Claude 模型返回的 metadata,Pi 可能提供 `low`、`medium`、`high`、`xhigh` 和 `max`;不可用的档位不会显示。Composer 2.5 只提供 `off`(标准)和 `max`(Max Mode)。Grok 提供 `low`、`medium`、`high` 和 `xhigh`。
|
|
37
|
+
|
|
38
|
+
## 要求
|
|
39
|
+
|
|
40
|
+
- Node.js 22.19 或更高版本。
|
|
41
|
+
- Pi 0.80 或兼容的更新版本。
|
|
42
|
+
- 有权使用所选模型的 Cursor 账号。
|
|
43
|
+
|
|
44
|
+
## 安装
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pi install npm:pi-provider-cursor-ask
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
重启 Pi 或执行 `/reload`,然后登录:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
/login cursor
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Provider 也可以复用受支持的 Cursor CLI 或桌面端凭证。自动化环境可设置 `CURSOR_ACCESS_TOKEN`。
|
|
57
|
+
|
|
58
|
+
## 使用
|
|
59
|
+
|
|
60
|
+
列出过滤后的模型:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pi --list-models cursor
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
可选择 `cursor/fable-5.1`、`cursor/fable-5`、`cursor/opus-5`、`cursor/opus-4.6`、`cursor/sonnet-5`;账号目录有时还可选 `cursor/grok-4.6` / `cursor/grok-4.6-fast`。
|
|
67
|
+
|
|
68
|
+
可用命令:
|
|
69
|
+
|
|
70
|
+
- `/cursor usage` — 打开 Cursor 套餐用量面板。
|
|
71
|
+
- `/cursor doctor` — 打开脱敏后的 provider 诊断面板。
|
|
72
|
+
|
|
73
|
+
若 Cursor 请求的历史在本地已缺失,本轮生成会以 `Refusing to answer empty` 明确失败,而不是发送残缺历史。重试即可从 Pi 对话历史重建。
|
|
74
|
+
|
|
75
|
+
若同时加载了 `@zhcsyncer/pi-meter`,底栏会跟当前 Cursor 模型走:Composer 看 Auto 池,Claude 行看 API 池。
|
|
76
|
+
|
|
77
|
+
本包有意占用 `cursor` provider id,作为旧扩展的直接替代品。不要与 `@rahularya01/pi-cursor` 同时加载;后注册的扩展会覆盖另一方的 `cursor` 模型目录。
|
|
78
|
+
|
|
79
|
+
## 安全
|
|
80
|
+
|
|
81
|
+
本 fork 保留上游读取本地 Cursor CLI/桌面端凭证及复用 Pi 现有 `cursor` 凭证条目的能力。若要禁用本地凭证发现,请在启动 Pi 前设置 `PI_CURSOR_SYSTEM_CREDENTIALS=0`,并改用 `/login cursor` 或 `CURSOR_ACCESS_TOKEN`。
|
|
82
|
+
|
|
83
|
+
Extension 以当前用户权限运行。安装前请审查代码,不要提交凭证,也不要把凭证粘贴进 issue。
|
|
84
|
+
|
|
85
|
+
## 许可证
|
|
86
|
+
|
|
87
|
+
MIT。上游版权和许可证声明保留在 [`LICENSE`](./LICENSE)。
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [1.4.25] - 2026-08-20
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Cursor never saw the conversation history or Pi's system prompt on a rebuilt request.** The provider carried history as `conversation_state.turns` structures, but Cursor's server builds the model prompt from `root_prompt_messages_json` and never renders turn structures back into prompt messages — so any request built without an upstream checkpoint (first turn of a resumed session, checkpoint discarded, conversation rotated, Pi restarted) reached the model as a single fresh question with no memory of the chat. The same list was carrying Pi's system prompt as a `{"role":"system"}` entry, which the server discards in favour of Cursor's own IDE prompt; that is why turns came back in Cursor's voice and called native Cursor tools (`Grep`, `read`) that do not exist in Pi. Requests built without a checkpoint now publish the system prompt as a `<rules>` user message and replay every completed turn as `user` / `assistant` / `tool` prompt messages, with historic tool calls named the way Cursor names MCP tools (`mcp_pi_<tool>`). Set `PI_CURSOR_PROMPT_HISTORY=0` to restore the old behaviour.
|
|
8
|
+
- **Every reasoning-model turn threw away a perfectly good checkpoint.** The history fingerprint that decides whether a stored checkpoint still matches Pi's transcript hashed thinking steps. The provider records a turn's steps as it streams and never records a thinking step, while Pi replays one on the next turn, so the two fingerprints could not agree for any model that emits reasoning. Each turn was scored as a rewritten history: checkpoint discarded, `conversationId` rotated, history rebuilt — into the path above that dropped it. Reasoning is now excluded from the fingerprint; a rewritten user turn or tool call is still detected.
|
|
9
|
+
- A conversation's system prompt is no longer pinned to whatever the first turn happened to say. Pi rewrites it as a session evolves (context-mode folds session memory into it), and a checkpoint froze the original; a changed prompt is now re-published onto the checkpointed conversation.
|
|
10
|
+
|
|
11
|
+
## [1.4.24] - 2026-08-20
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **Unnamed InteractionQuery field 9 no longer kills the in-flight turn.** 1.4.23 fail-closed without sending an `InteractionResponse`, so Cursor parked and `processServerMessage` threw (`stopReason: error`). Field 9 is still rejected (not approved); we now answer with a reject-shaped response so the stream continues. Fixes [#10](https://github.com/Rahularya01/pi-cursor/issues/10).
|
|
16
|
+
- **Idle/transport restart after a tool pause matches Pi's in-flight turn, not the bridge suffix.** Multi-round chains and a second bridge loss in the same turn were dying with `pending_tool_call_mismatch` because recovery compared the last writeNativeStream round against every tool result Pi replayed. Resume planning now uses the parsed client turn; recovered streams carry a `ClientTranscript` so mid-pause snapshots stay keyed to Pi's history. Duplicate re-emitted exec ids are collapsed (last result wins). Ports the diagnoses from [#8](https://github.com/Rahularya01/pi-cursor/pull/8) and [#9](https://github.com/Rahularya01/pi-cursor/pull/9).
|
|
17
|
+
- **Blob store entry bound evicts oldest-first instead of failing the conversation.** Crossing 512 distinct blobs threw on every later turn. Eviction happens before the write is acked; an incoming blob that cannot fit even in an empty store is still rejected without punching holes. Inspired by [#11](https://github.com/Rahularya01/pi-cursor/pull/11).
|
|
18
|
+
|
|
19
|
+
## [1.4.23] - 2026-08-19
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- **Tool continuation after an idle timeout no longer discards a valid checkpoint as `stale_checkpoint`.** Abort/idle persistence treated the in-flight turn as completed (`checkpointTurnCount + 1`) and cleared mid-pause metadata, so the next retry skipped recovery. In-flight checkpoints are now keyed to the completed-turn history only. Fixes [#5](https://github.com/Rahularya01/pi-cursor/issues/5).
|
|
24
|
+
- **`/login cursor` is no longer overridden by IDE/CLI credentials.** Cascade is now env → Pi OAuth → Keychain → IDE DB. Rotated OAuth refresh tokens are written back to `auth.json`.
|
|
25
|
+
- **WSL no longer reads every Windows user's Cursor `state.vscdb`.** Only the current Windows account (`USERPROFILE` / `USERNAME`) is considered.
|
|
26
|
+
- **Unknown Cursor exec messages fail closed** instead of sending a guessed empty MCP result.
|
|
27
|
+
- **Web/search InteractionQuery is rejected by default**; unnamed proto field 9 and Cursor mode-switches no longer auto-approve.
|
|
28
|
+
- Refresh error bodies and debug logs redact refresh tokens / JWTs. `security-check` also flags committed JWTs and session cookies. README engines match Node `>=22.19.0`.
|
|
29
|
+
|
|
30
|
+
## [1.4.22] - 2026-08-18
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- **Greetings and "who are you" were answered in Cursor's voice, not Pi's.** Trivial conversational turns drop tools and blank the system prompt so a bare "hi" does not spend tens of thousands of input tokens on the agent prompt. The allowlist also held identity and capability questions — `who are you`, `what can you do for me`, `tell me about yourself` — whose answer _is_ the system prompt, so exactly those turns reached Cursor carrying no prompt at all and came back describing Cursor's IDE assistant. The allowlist is now split: pleasantries still drop the prompt, identity and capability turns keep it, and both still omit tools. A dropped prompt is no longer empty either — it carries a one-line "You are running inside Pi, not the Cursor IDE", so a greeting cannot be answered in Cursor's voice either. `tools_omitted` records whether the prompt was dropped.
|
|
35
|
+
- **The bundled fallback catalog under-reported the context window of every 1M Claude model by 5x.** Ten rows — `claude-4.6-opus-high`, `claude-4.6-opus-max`, `claude-4.6-sonnet-medium`, `claude-4.5-sonnet`, `claude-4-sonnet-1m` and their `-thinking` variants — carried `contextWindow: 200000` while their own display names read "1M". Live discovery infers the window from the id and name and had these right; only the offline snapshot was wrong, so the bad number surfaced precisely when discovery was unavailable. The rows are corrected, and `FALLBACK_MODELS` now derives `contextWindow` the same way it already derived `reasoning`, so the file cannot drift back out of agreement.
|
|
36
|
+
- **Every model advertised a 64K output ceiling.** `maxTokens` was a hardcoded `64_000` at all three places a model row is built, so Claude 4.6 and the GPT-5 family were reported at half their real limit. Cursor's `ModelDetails` carries no output ceiling, so it is now inferred from the id and display name alongside the context window: Claude 4.6+ and GPT-5 report 128K, and everything else — Claude 4.5 and older, Haiku 4.5, Composer, Gemini, Grok, Kimi, and `Auto` — keeps the 64K floor. This is Pi-side budgeting metadata only; the Cursor run request has no output-token field.
|
|
37
|
+
|
|
38
|
+
### Internal
|
|
39
|
+
|
|
40
|
+
- Context-window and output-token inference moved to a dependency-free `src/models/limits.ts`, re-exported from `src/stream/model-discovery.ts`. Importing them directly would have made the startup-path model catalog pull in the bridge and HTTP/2 transport modules at runtime, where it previously had only an erased `import type`.
|
|
41
|
+
|
|
42
|
+
## [1.4.21] - 2026-08-18
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- **Session switch/fork/shutdown deleted the on-disk conversation journal.** Switching chats (or `/fork`, `/tree`, shutdown) killed the HTTP/2 bridge _and_ `unlink`d the journal that `/resume` hydrates from. The next turn in that session had no Cursor checkpoint and rebuilt without the compacted summary — it looked like the chat had forgotten the conversation. Those hooks now only tear down bridges; the journal stays until TTL eviction.
|
|
47
|
+
- **Trivial turns (`hi` / `ok`) blanked a system prompt that held folded session memory.** Greetings omit tools _and_ used to drop the system prompt to save tokens. After compaction that prompt is where the recovered `<session_state>` lives, so a short follow-up started from a blank slate. The prompt is kept when it contains provider-context / session-resume memory; tools are still omitted.
|
|
48
|
+
- **Compaction and resume summaries were framed as disposable infrastructure.** The same "latest user message is the only task; do not continue prior work" banner wrapped live context-mode injections _and_ recovered `<summary>` / `<session_resume>` blocks, so the model treated the compacted memory as noise. Resume/compaction side-channels now say they are active memory to continue from. Empty hierarchy+mode-only injections are still dropped; a real `<summary>` is kept even when short. Trailing user text after `</session_state>` is no longer capped at 500 characters.
|
|
49
|
+
- **A compacted Pi transcript kept the old Cursor `conversationId`.** When turn count or history fingerprint no longer matched the checkpoint, the checkpoint was discarded but the id stayed, so the next rebuild attached to a Cursor conversation whose history no longer existed. Those mismatches now rotate `conversationId`. A KV blob miss does the same: drop the checkpoint, rotate, persist — instead of answering the miss with an empty blob and leaving the hole in place.
|
|
50
|
+
- **Replayed history dropped thinking.** Pi thinking blocks never became Cursor `ThinkingMessage` steps, so a rebuild after checkpoint loss lost the reasoning that earlier turns had produced. Thinking is now carried on the OpenAI-shaped assistant message and encoded as a turn step.
|
|
51
|
+
- **Native Cursor execs (read / shell / …) stalled or listed the workspace to "recover" context.** Rejects now name the matching Pi MCP tool when one is advertised (`read` → `read`, `shellArgs` → `bash`, …). The system prompt also states the session is running inside Pi, not Cursor IDE.
|
|
52
|
+
|
|
53
|
+
### Performance
|
|
54
|
+
|
|
55
|
+
- **The HTTP/2 bridge process is reused across user turns.** Each turn previously spawned `h2-bridge.mjs` and did a fresh TLS + HTTP/2 handshake. A completed stream now keeps the child and session; the next turn sends `{"cmd":"open"}` and a new Connect stream. Spawn + handshake remain only for the first turn, after an idle TTL, or when the session is switched away. Mid-tool pauses still hold the live stream as before.
|
|
56
|
+
|
|
57
|
+
## [1.4.20] - 2026-08-18
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
|
|
61
|
+
- **An interrupted assistant turn replayed as one that simply trailed off.** Cursor's turn structure carries only the text a turn produced, so a turn that was aborted, errored, or truncated came back on the next request indistinguishable from a model that chose to stop — pi's `stopReason` and `errorMessage` were dropped entirely. Resuming a session after an interrupted turn therefore looked to the model like missing context rather than incomplete work: in the session that surfaced this, "continue please" sent the model listing the workspace and reading unrelated agent transcripts, from which it confabulated a prior discussion that never happened. Completed turns are untouched; a turn that did not finish now carries an explicit trailing note (`[pi-cursor: this assistant turn was interrupted before it finished; …]`) placed after any tool calls it managed to emit. Error detail rides along, redacted through `redactSecrets()` and capped at 200 characters. A trailing interrupted turn — the one being retried, not history behind us — is deliberately left unannotated so the live user text is not stranded.
|
|
62
|
+
- **Conversation journals silently dropped all but the newest 64 blobs.** The live blob store holds up to `MAX_ACTIVE_BLOB_ENTRIES` (512) entries, but the on-disk journal that survives a restart persisted only 64. A checkpoint addresses its history by blob id, so a restored checkpoint referencing an evicted blob asked for content that was gone — and `getBlobArgs` answers a miss with an empty result, which is indistinguishable from an empty blob. The conversation came back structurally intact with its older turns blank, with no error at any layer. Journals now persist the whole store under a byte budget derived from the record's actual checkpoint size, and a record that still could not fit everything is marked so the reader drops its checkpoint and rebuilds from pi's transcript instead of resuming with holes. Roughly 15–20 turns was enough to cross the old cap.
|
|
63
|
+
- **A blob miss is no longer invisible.** `getBlobArgs` for a blob we do not hold now records `kv_blob_miss` in the lifecycle log and in `/cursor.doctor`'s `lastStreamEvent`, so this class of silent history loss is diagnosable from the sanitized log alone.
|
|
64
|
+
|
|
65
|
+
## [1.4.19] - 2026-08-17
|
|
66
|
+
|
|
67
|
+
### Performance
|
|
68
|
+
|
|
69
|
+
- **Stopped reading whole journals to check one timestamp.** The run-journal TTL sweep runs once per user turn, on the main thread, and read plus `JSON.parse`d every journal file — megabytes of base64 blobs each — only to look at the `savedAt` field near the front of the record. It now reads a 512-byte head through a single file descriptor, falling back to a full parse only when the head does not carry the field; stale journals are rejected from the same head instead of decoding their blobs first. ~138x faster over a 25-journal cache directory (896ms → 6.5ms).
|
|
70
|
+
- **Image dedup no longer hashes every payload.** `mergeImages()` sha256'd every image on every history replay. Duplicates must agree on MIME type and byte length, so shapes are bucketed first and only images colliding on shape are digested, with digests memoized by buffer identity. ~700x faster replaying a 12-image transcript, and ~5x on cold buffers with distinct sizes.
|
|
71
|
+
- **Removed a `process.env` read from the per-token path.** `debugLog()` re-resolved `PI_CURSOR_PROVIDER_DEBUG` on every call, including once per streamed token. `process.env` is a native-backed proxy costing roughly 100x an ordinary property read, which made it the single largest cost in `processServerMessage()`. The flag is now resolved once, lazily. ~8x faster per server message.
|
|
72
|
+
- **Fixed O(n²) model catalog building on the activation path.** `hasVariantParameterSet()` re-normalized all of a model's variants for each of that model's variants, so catalog building scaled quadratically in string sorts. The advertised parameter sets are now derived once per model. ~5x faster, taking the whole activation model chain from 3.75ms to 1.0ms. The canonical key sorts also moved off `localeCompare`, which was needlessly slow and could rank distinct strings as equal — leaving the key dependent on input order.
|
|
73
|
+
- **Dropped dead work from side-channel splitting.** `splitUserTextAndSideChannel()` evaluated seven regexes and seven full-string trims per user message inside an `if` block with an empty body, then discarded the result.
|
|
74
|
+
- **Memoized journal blob encoding.** A conversation's blobs are carried over unchanged across the journal writes triggered by each tool-call pause, so their base64 encoding is now cached by buffer identity rather than recomputed per write.
|
|
75
|
+
|
|
76
|
+
No behavior change; startup module load was measured and deliberately left alone (the extension's own bundle imports in ~13ms — the rest is pi's peer dependencies).
|
|
77
|
+
|
|
78
|
+
## [1.4.18] - 2026-08-16
|
|
79
|
+
|
|
80
|
+
### Added
|
|
81
|
+
|
|
82
|
+
- **Forensic diagnostics for a desynced Connect frame boundary.** If a `Connect message exceeds N bytes` desync recurs, `PI_CURSOR_PROVIDER_DEBUG=1`'s lifecycle log now captures the bytes consumed and frames parsed before the desync, the raw frame header, and up to 32 trailing context bytes — enough to tell a real corrupted stream apart from a parser bug without needing a live repro. No cost when debug logging is off.
|
|
83
|
+
|
|
84
|
+
## [1.4.17] - 2026-08-16
|
|
85
|
+
|
|
86
|
+
### Fixed
|
|
87
|
+
|
|
88
|
+
- **A corrupted/misaligned incoming Connect frame (`Connect message exceeds 67108864 bytes`) no longer fails the turn outright.** This case bypassed the existing transport-loss retry machinery used for every other bridge failure (GOAWAY, connection reset, auth, ...). It's now treated the same way: the bridge is killed and, since the desync is local per-connection state rather than a permanent condition, the turn resumes over a fresh connection via checkpoint/history recovery when possible, falling back to the same error as before only when a retry isn't safe or attempts are exhausted.
|
|
89
|
+
- Added a randomized differential test for the Connect frame reassembly logic (chunk-boundary fragmentation, large frames split across many tiny reads), which also caught and fixed a correctness bug in the chunk accumulator introduced in 1.4.16 — verified byte-for-byte against a reference implementation across many trials.
|
|
90
|
+
|
|
91
|
+
## [1.4.16] - 2026-08-16
|
|
92
|
+
|
|
93
|
+
### Performance
|
|
94
|
+
|
|
95
|
+
- **Eliminated O(n²) frame reassembly on the streaming hot path.** The bridge's stdout reader, the Connect frame parser, and `h2-bridge.mjs`'s stdin reader all re-concatenated the entire buffered backlog on every incoming chunk, which is quadratic in a frame's total size once it arrives split across many small reads (large tool results, images, checkpoints). Replaced with a chunk-array accumulator that only merges what's needed to make progress — up to ~690x faster reassembling a large frame from small chunks in benchmarks.
|
|
96
|
+
- **Cached checkpoint history fingerprinting.** `fingerprintCompletedTurns()` re-serialized and hashed the full completed-turn history from scratch on every call, even though it runs multiple times per turn over overlapping turn arrays. Added a per-turn cache keyed by turn-object identity.
|
|
97
|
+
- **Memoized MCP tool schema slimming.** `buildMcpToolDefinitions()` and the derived MCP tool-name list re-slimmed and re-encoded every tool's schema on every call, even when the underlying tool set was unchanged from the previous turn. Both are now cached by array identity.
|
|
98
|
+
|
|
99
|
+
## [1.4.15] - 2026-08-15
|
|
100
|
+
|
|
101
|
+
### Documentation
|
|
102
|
+
|
|
103
|
+
- **README Onboarding & Scannability:** Restructured README to prioritize quick setup and clear usage steps, added a table of contents, and moved detailed environment variable and architectural reference material into collapsible `<details>` blocks.
|
|
104
|
+
|
|
105
|
+
### Refactored
|
|
106
|
+
|
|
107
|
+
- **Credential Handling & Import Cleanup:** Consolidated credential source definitions into a dedicated `CredentialSource` enum for improved type safety and consistency across auth modules. Streamlined imports, refined system credential policy helpers, and removed unused legacy code.
|
|
108
|
+
|
|
109
|
+
## [1.4.14] - 2026-08-15
|
|
110
|
+
|
|
111
|
+
### Fixed
|
|
112
|
+
|
|
113
|
+
- **`Connect message exceeds 67108864 bytes` recurring on every turn of a long-running conversation.** The upstream checkpoint Cursor hands back each turn was replayed into every request with no size cap, unlike the rest of the pipeline (tool results, blobs). Once it grew past the transport's 64 MiB frame limit, every later turn failed permanently. It is now discarded and rebuilt from the (already-bounded) blob store once it exceeds 48 MiB.
|
|
114
|
+
- Both the outgoing and incoming Connect-frame size errors now report the actual byte count, direction, and where to look (`/cursor.doctor`'s `lastRequestSize`, or `PI_CURSOR_PROVIDER_DEBUG=1`) instead of a bare byte limit.
|
|
115
|
+
- `sanitizeText()` no longer mangles valid Unicode surrogate pairs (emoji, astral-plane characters) — it now strips only lone/unpaired surrogates.
|
|
116
|
+
- `buildSelectedContextBlob()` now varint-encodes field lengths instead of writing a single raw length byte, preventing silent wire corruption if a future caller passes a value >=128 bytes.
|
|
117
|
+
- `/cursor.usage` no longer throws on a non-numeric billing-cycle timestamp from Cursor's usage endpoint.
|
|
118
|
+
|
|
119
|
+
## [1.4.13] - 2026-08-15
|
|
120
|
+
|
|
121
|
+
### Fixed
|
|
122
|
+
|
|
123
|
+
- **Whole-project reviews failing with `Connect message exceeds 67108864 bytes`.** Individual tool text results are now capped at 512 KiB, with an explicit truncation notice that tells the agent to retry with a narrower command or range.
|
|
124
|
+
- Tool images are bounded to a 16 MiB per-result budget, preventing a single oversized result from exhausting the bridge while retaining smaller images that fit.
|
|
125
|
+
- Oversized tool payloads are normalized before journaling and are no longer copied into debug logs, reducing memory, disk, and follow-up token usage.
|
|
126
|
+
|
|
127
|
+
## [1.4.12] - 2026-08-15
|
|
128
|
+
|
|
129
|
+
### Fixed
|
|
130
|
+
|
|
131
|
+
- **Pi host process exits during rapid tool chains.** Child-process spawn errors, pipe errors, malformed frames, and exceptions from bridge data/close consumers are now contained as request-level bridge failures instead of escaping Node event callbacks and terminating Pi.
|
|
132
|
+
- Bridge output that arrives before the stream consumer is registered is buffered with a hard size limit instead of being silently dropped.
|
|
133
|
+
- Added regression coverage for `EAGAIN`-style spawn failures, callback exceptions, oversized frames, and early bridge output.
|
|
134
|
+
|
|
135
|
+
## [1.4.11] - 2026-08-15
|
|
136
|
+
|
|
137
|
+
### Fixed
|
|
138
|
+
|
|
139
|
+
- **Excessive token usage on conversational prompts.** Trivial greetings and capability questions now omit both MCP tools and the large agent system prompt, while actionable requests retain the full context.
|
|
140
|
+
- `/cursor.doctor` now reports the actual lifecycle log path.
|
|
141
|
+
|
|
142
|
+
## [1.4.10] - 2026-08-15
|
|
143
|
+
|
|
144
|
+
### Fixed
|
|
145
|
+
|
|
146
|
+
- Hardened permission handling, transport framing, OAuth cancellation, recovery journals, logging, and MCP tool validation.
|
|
147
|
+
- Startup model discovery now uses stale-while-revalidate behavior so Pi can activate from cached or bundled models without waiting for network discovery.
|
|
148
|
+
- Added bounded payloads, backpressure handling, cleanup on aborted/failing streams, and expanded regression coverage.
|
|
149
|
+
|
|
150
|
+
## [1.4.9] - 2026-08-12
|
|
151
|
+
|
|
152
|
+
### Fixed
|
|
153
|
+
|
|
154
|
+
- **Tool continuation recovery after a silent resumed bridge.** Idle-timeout, abort, and transport-retry persistence now retain the mid-pause checkpoint and pending tool-call metadata when a tool result is being resumed, preventing valid checkpoints from being discarded as stale after the 3-minute watchdog fires.
|
|
155
|
+
- Added a recovery guard that refuses to replay tool results into a checkpoint when no matching durable mid-pause snapshot exists.
|
|
156
|
+
|
|
157
|
+
## [1.4.8] - 2026-08-02
|
|
158
|
+
|
|
159
|
+
### Fixed
|
|
160
|
+
|
|
161
|
+
- **`stale_checkpoint` error after tool calls when the bridge is lost.** Root cause traced via the durable journal: `commitStoredCheckpoint` records `checkpointTurnCount = completedTurns + 1` (it includes the just-finished turn). When a tool-result recovery request arrives, `turns.length` is still the pre-tool count (one less), so `discardStaleCheckpointIfNeeded` treated the valid checkpoint as stale, cleared both the checkpoint and mid-pause metadata, and left `planRecovery` with nothing to work with. The staleness check now allows the off-by-one when `midPause` metadata confirms the request is a tool continuation for that exact turn — the checkpoint is preserved for `planRecovery` to use.
|
|
162
|
+
|
|
163
|
+
## [1.4.7] - 2026-08-02
|
|
164
|
+
|
|
165
|
+
### Fixed
|
|
166
|
+
|
|
167
|
+
- **Pi Lens automated context displaced the real user prompt.** Messages explicitly labeled `[pi-lens automated context — not a user request]` (and other `[pi-lens automated …]` variants) were not recognized as provider infrastructure. When appended after `hi`, Pi Cursor treated `hi` as history and the Pi Lens file-safety notice as the active task, causing replies such as “I'll re-read tests/request-size.test.ts before editing it.” These notices now move into `<provider_context>` while the actual user text remains the live turn.
|
|
168
|
+
- Handles both separate-message and concatenated forms (`hi\n\n[pi-lens automated …]`) with regression coverage derived from the durable journal payload.
|
|
169
|
+
|
|
170
|
+
## [1.4.6] - 2026-08-02
|
|
171
|
+
|
|
172
|
+
### Fixed
|
|
173
|
+
|
|
174
|
+
- **Trivial conversational turns no longer send tool schemas.** Exact greetings and acknowledgements such as `hi`, `hello`, `thanks`, and `sounds good` cannot require repository/MCP tools, yet previously paid for all 48 contracts. These turns now omit tools entirely; actionable text such as `hi, inspect src` still receives the full compact tool surface.
|
|
175
|
+
- Adds a `tools_omitted` lifecycle event with the original tool count. On the measured 48-tool `hi` request this should reduce estimated input from ~16.7k tokens to ~8.5k (roughly 10% → 5% for the current model). The remaining floor is Pi's system/project prompt.
|
|
176
|
+
|
|
177
|
+
## [1.4.5] - 2026-08-02
|
|
178
|
+
|
|
179
|
+
### Fixed
|
|
180
|
+
|
|
181
|
+
- **Further reduced simple-turn context usage.** Cursor's protobuf `google.protobuf.Value` encoding amplifies verbose JSON Schema annotations. Slim mode now removes parameter-level descriptions and other annotation-only fields while preserving the executable tool contract: property names, types, required fields, unions, enums, and validation constraints. Function descriptions are reduced to one concise sentence. Synthetic verbose-tool payloads shrink by about 83%.
|
|
182
|
+
- Corrected `/cursor.doctor`'s `approxTokens` estimate. It previously double-counted tool schemas and system content already included in request/blob bytes. It now estimates from actual wire bytes only and reports `wireBytes` explicitly.
|
|
183
|
+
|
|
184
|
+
## [1.4.4] - 2026-08-02
|
|
185
|
+
|
|
186
|
+
### Fixed
|
|
187
|
+
|
|
188
|
+
- **Simple turns looked like they "used 20% context".** The visible context-mode hierarchy blurb is tiny; the real cost is Pi's system prompt + full tool/MCP JSON schemas (often tens of thousands of tokens) re-sent every turn. pi-cursor now:
|
|
189
|
+
- drops no-op context-mode injections (hierarchy boilerplate + empty/mode-only `<session_state>`)
|
|
190
|
+
- slims tool descriptions/parameter docs/enums before building Cursor MCP tool defs (**default on**; `PI_CURSOR_SLIM_TOOLS=0` to disable)
|
|
191
|
+
- records a request-size breakdown on every stream (`lifecycle` `request_size` + `/cursor.doctor` `lastRequestSize`)
|
|
192
|
+
|
|
193
|
+
## [1.4.3] - 2026-08-02
|
|
194
|
+
|
|
195
|
+
### Fixed
|
|
196
|
+
|
|
197
|
+
- **Context-mode / compaction injections swallowed the real user message.** When Pi appended `context-mode active…` / `<session_state>` to the same user turn as the actual prompt (e.g. `hi\n\ncontext-mode active…`), the whole turn was classified as side-channel and folded into the system prompt — leaving an empty user task. Models then answered the prior session summary ("I'll re-read those three files…") instead of the new message. Mixed messages are now split: infrastructure blocks move to `<provider_context>`, and the residual user text stays as the live turn. Priority framing also states that the latest user message is the only task.
|
|
198
|
+
|
|
199
|
+
## [1.4.2] - 2026-08-02
|
|
200
|
+
|
|
201
|
+
### Fixed
|
|
202
|
+
|
|
203
|
+
- **npm publish CI failed with E403 after a manual publish.** The tag workflow always ran `npm publish`, so when a version was already on the registry it failed the release job. Publish now skips cleanly if `${name}@${version}` already exists, and asserts the git tag matches `package.json`.
|
|
204
|
+
|
|
205
|
+
## [1.4.1] - 2026-08-02
|
|
206
|
+
|
|
207
|
+
### Fixed
|
|
208
|
+
|
|
209
|
+
- **Long sessions dying with bridge/idle timeouts.** After partial assistant output, transport loss (GOAWAY, bridge crash, silence) previously hard-failed because blind retries were blocked to avoid duplicated text. Recovery now continues from the latest upstream **checkpoint** even when text/thinking already streamed — Cursor resumes server-side state and emits only new tokens, which Pi appends.
|
|
210
|
+
- **H2 activity idle default no longer kills healthy long runs.** `PI_CURSOR_H2_IDLE_TIMEOUT_MS` defaults to `0` (disabled). Parent heartbeats already keep the bridge alive; the previous 15-minute default was a common mid-session `Bridge connection lost` source.
|
|
211
|
+
- **Parked tool bridges no longer expire from the original park timestamp alone.** Heartbeats slide the active-bridge TTL forward during multi-round tool chains.
|
|
212
|
+
- **Vague `Bridge connection lost` errors.** Failures are classified (GOAWAY / reset / auth / timeout / crash) with retryability and actionable hints.
|
|
213
|
+
|
|
214
|
+
### Added
|
|
215
|
+
|
|
216
|
+
- **Durable run journal** (`src/stream/run-journal.ts`) under the pi-cursor cache dir. Checkpoints, mid-pause tool metadata, and referenced blobs survive bridge death so tool continuation / checkpoint resume can hydrate after a lost in-memory map.
|
|
217
|
+
- **Transport failure classifier** (`src/stream/transport-errors.ts`) and checkpoint-continuation prompt used by the stream runtime.
|
|
218
|
+
- Bridge handles expose `lastStderr()` for diagnostics.
|
|
219
|
+
- Unit coverage in `tests/transport-recovery.test.ts` for recovery policy, failure classification, timeout defaults, and journal round-trip.
|
|
220
|
+
|
|
221
|
+
### Changed
|
|
222
|
+
|
|
223
|
+
- Stream silence watchdog defaults: `PI_CURSOR_STREAM_IDLE_TIMEOUT_MS` / `PI_CURSOR_RESUME_IDLE_TIMEOUT_MS` → **180000 (3 min)**; `PI_CURSOR_STREAM_IDLE_MAX_RETRIES` → **5**.
|
|
224
|
+
- Docs (README, AGENTS, protocol) aligned with the real runtime defaults.
|
|
225
|
+
|
|
226
|
+
## [1.4.0] - 2026-07-29
|
|
227
|
+
|
|
228
|
+
### Fixed
|
|
229
|
+
|
|
230
|
+
- **Extension initialization took 10–15 seconds.** Activation now completes in **3–12ms** (measured; previously ~6.8s of blocking work before pi could continue). Three independent causes, all on the critical path:
|
|
231
|
+
- **A doomed token refresh on every launch (~2.6s).** The credential cascade tried the macOS Keychain first and, finding the Cursor CLI's access token expired, POSTed a refresh that could never succeed — the CLI writes the _same expired token_ into `cursor-refresh-token`, so `exchange_user_api_key` answers `Invalid User API Key` — before falling through to the Cursor IDE database, which resolved in 2ms. Both system sources are now read concurrently and every locally stored token is checked before any network exchange, so a valid token is never two milliseconds away behind a failing one. Resolution: **2762ms → 214ms**.
|
|
232
|
+
- **Blocking model discovery (~4s).** `await discoverStartupModels()` ran two unary RPCs before the provider was registered at all. Discovery moved to pi's `refreshModels(context)` hook, which pi calls in the background and again whenever `/model` is opened; `allowNetwork:false` and aborted signals return the current rows without touching the network.
|
|
233
|
+
- **Nothing survived the process.** The model cache was in-memory with a 5-minute TTL, so every new pi process re-paid full discovery. The catalog is now persisted to disk and read synchronously at startup.
|
|
234
|
+
- v1.3.4 added the startup `await` specifically so the full live catalog (Grok, Luna, Kimi) was registered upfront. That still holds — the persisted catalog means launches register the real discovered list (147 models here), not the bundled fallback — but it no longer costs a blocking round-trip.
|
|
235
|
+
|
|
236
|
+
### Added
|
|
237
|
+
|
|
238
|
+
- **Persistent model catalog cache** (`src/stream/model-cache.ts`) at `$XDG_CACHE_HOME/pi-cursor` (override with `PI_CURSOR_CACHE_DIR`). Stores the raw Cursor model shapes rather than pi `ModelConfig` rows, because the effort/max-mode routing `streamSimple` depends on does not survive that conversion. Version-stamped, 30-day max age, and tolerant of a corrupt or unwritable cache.
|
|
239
|
+
- **Refresh back-off** (`src/auth/refresh-guard.ts`). A refresh token that fails is remembered for 10 minutes and not retried, so a permanently-stale Cursor CLI keychain entry costs nothing on subsequent launches. The back-off is disk-backed and survives restarts; only a SHA-256 prefix is stored, never the token.
|
|
240
|
+
- **In-process HTTP/2 for unary RPCs** (`src/client/h2-unary.ts`). Model discovery no longer spawns a child process per call, saving ~1.5s of local overhead across the two RPCs. The h2-bridge subprocess still carries the bidirectional chat stream, where Bun's `node:http2` is unusable, and remains the automatic fallback if the in-process client fails. Force the old path with `PI_CURSOR_UNARY_BRIDGE=1`.
|
|
241
|
+
- `/cursor.doctor` reports `catalogCache`, `catalogCacheDir`, and `unaryTransport`.
|
|
242
|
+
|
|
243
|
+
### Changed
|
|
244
|
+
|
|
245
|
+
- `PI_OFFLINE` now skips live model discovery entirely rather than only skipping it at startup.
|
|
246
|
+
- `tokenSource` starts as `none` and fills in on the first stream or background refresh, since activation no longer resolves a credential. A `/cursor.doctor` run in the first second of a session may show `tokenSource=none`.
|
|
247
|
+
|
|
248
|
+
## [1.3.2] - 2026-07-26
|
|
249
|
+
|
|
250
|
+
### Fixed
|
|
251
|
+
|
|
252
|
+
- **`No API provider registered for api: cursor-native`.** The native transport was only attached via `pi.registerProvider({ streamSimple })`. Pi's Agent still dispatches through the global compat `streamSimple` registry on some hosts/entry paths, and ModelRuntime falls back to that same registry for custom `model.api` values. The extension now also calls `registerApiProvider({ api: "cursor-native", ... })` and stamps `api: "cursor-native"` on every model config so the dispatcher can find the stream implementation.
|
|
253
|
+
|
|
254
|
+
## [1.3.1] - 2026-07-25
|
|
255
|
+
|
|
256
|
+
### Fixed
|
|
257
|
+
|
|
258
|
+
- **Tool continuation was unrecoverable after the first tool round.** Losing the upstream bridge mid-tool failed with `Cursor tool continuation was lost … skipReason=pending_tool_call_mismatch` on every round after the first. The mid-pause snapshot records only the round that was parked, but the client re-sends every tool result in the in-flight user turn, and recovery demanded the two sets be equal. The parked set must instead be _covered by_ what arrived; the in-flight turn is still matched exactly, which is what pins the replayed transcript to the client's view.
|
|
259
|
+
- **Parallel tool calls beyond the first never reached the client.** Cursor can frame several execs in one chunk, but the response was closed on the first, so the rest were silently dropped and only re-offered if the bridge happened to survive. The pause is now deferred to the end of the chunk. Only execs the client was actually told about are recorded as pending, since recovery can only expect back what the client saw.
|
|
260
|
+
- **Checkpoints delivered during a tool pause were discarded.** The latest checkpoint was held in per-round state while the bridge outlived the round, so anything arriving mid-pause was stranded in the previous round's closure — a recurring cause of `hadStoredCheckpoint=false` diagnostics. It now lives on the bridge.
|
|
261
|
+
- **An oversized or unsupported image broke every later turn.** The whole history is re-parsed on each request and an image failing Cursor's 5 MiB / format check threw, so one bad screenshot — typically from a tool result — permanently failed the conversation. Images already in the transcript are now decoded leniently; the message being sent still errors, since that one the caller can fix.
|
|
262
|
+
- **An undecodable checkpoint was never discarded**, failing every subsequent turn in the conversation. It is now decoded once during staleness validation and dropped on failure, degrading to a rebuild.
|
|
263
|
+
- **The most load-bearing blob was first to be evicted.** `trimBlobStore` drops oldest-first, but merging used `Map.set`, which leaves an existing key at its original position — so the system-prompt blob, written first on every build and referenced by every checkpoint, was permanently the oldest entry. Merging now re-inserts, making eviction genuinely least-recently-referenced.
|
|
264
|
+
- **Tool-result images were dropped on checkpoint recovery**, though the full-history rebuild path preserved them.
|
|
265
|
+
- Tool results with no `tool_call_id` are excluded from recovery's set matching instead of reading as duplicates and failing an otherwise sound recovery.
|
|
266
|
+
- A live bridge is no longer resumed when the request's history does not match the one it was parked on. Without a Pi session id the bridge key is only a hash of the opening user message, so two conversations that start alike shared a key.
|
|
267
|
+
|
|
268
|
+
## [1.3.0] - 2026-07-24
|
|
269
|
+
|
|
270
|
+
### Added
|
|
271
|
+
|
|
272
|
+
- **Wire-drift detection.** Unrecognized `agent.v1` server messages and unknown protobuf fields are no longer skipped silently. They are counted, written to the lifecycle log as `wire_drift`, appended to the failing turn's error message, and listed by `/cursor.doctor` (`lastDriftSignal`, `wireDrift`, `wireDriftStranding` plus a detail block). `wireDriftStranding=yes` distinguishes an unanswered message that could have parked the turn from a merely out-of-date schema — previously both surfaced as a bare idle timeout.
|
|
273
|
+
- **Reproducible protobuf codegen.** `proto/agent.proto` is now vendored as the source of truth for `src/proto/agent_pb.ts`, with `npm run proto:gen` (regenerate), `npm run proto:sync` (recover the `.proto` from an updated generated file — protoc-gen-es embeds the full descriptor), and `npm run proto:check` (fails the build when the two drift apart, and is part of `npm run check`). Uses `buf` + `protoc-gen-es` from devDependencies, so no system `protoc` is required. See [`proto/README.md`](proto/README.md).
|
|
274
|
+
- `npm run smoke:wire` performs the real Connect/HTTP2 handshake against the configured endpoint and reports schema drift without starting a chat turn.
|
|
275
|
+
|
|
276
|
+
### Changed
|
|
277
|
+
|
|
278
|
+
- **`src/stream/native-core.ts` split into focused modules** (5,696 → ~1,650 lines): `types`, `tuning`, `debug-log`, `images`, `model-discovery`, `message-parsing`, `pi-adapter`, `request-build`, `bridge-session`, `session-state`, `server-messages`, `thinking-filter`, and `drift`. The public surface of `src/stream/index.ts` is unchanged.
|
|
279
|
+
- `native-core.ts` is now covered by ESLint and Prettier (it was previously exempted for being too large), which removed a large amount of dead code and unused imports.
|
|
280
|
+
- Shared structural types are declared once in `src/stream/types.ts`; `recovery.ts` and `native-core.ts` previously carried duplicate copies of `ParsedTurn`, `StoredConversation`, and friends.
|
|
281
|
+
|
|
282
|
+
### Removed
|
|
283
|
+
|
|
284
|
+
- **The quarantined OpenAI-compatible local proxy.** `startProxy`/`stopProxy` and the entire parallel request path (`handleChatCompletion`, `writeSSEStream`, `handleToolResultResume`, `handleNonStreamingResponse`, and helpers) are gone — roughly 1,250 lines that were unreachable from the provider. Native `streamSimple` was already the only chat path; `/cursor.doctor` now reports `proxyPath=removed`.
|
|
285
|
+
|
|
286
|
+
## [1.2.3] - 2026-07-24
|
|
287
|
+
|
|
288
|
+
### Fixed
|
|
289
|
+
|
|
290
|
+
- **Permanent hang guard.** A stream that receives no upstream progress of any kind now recovers/retries or ends the turn with a clear error instead of parking forever. Since 1.2.1 disabled the idle watchdog by default, any un-answered exec or silent/dropped upstream left the run "stuck on working" indefinitely (observed: a turn parked ~26 min until manually aborted). The watchdog is re-enabled by default as a **silence** guard: `PI_CURSOR_STREAM_IDLE_TIMEOUT_MS` / `PI_CURSOR_RESUME_IDLE_TIMEOUT_MS` default to `120000` (2 min) and `PI_CURSOR_STREAM_IDLE_MAX_RETRIES` to `2`. Every server signal (text/thinking/token deltas, tool-call events, thinkingCompleted, heartbeat, summary, answered interaction/exec) counts as progress and resets it, and it is paused during tool execution — so long reasoning turns and slow tools are unaffected; it only fires on a genuine park. Set the env vars to `0` to restore the previous unbounded behavior.
|
|
291
|
+
|
|
292
|
+
### Added
|
|
293
|
+
|
|
294
|
+
- `execServerMessage` handling is now recorded in the lifecycle log (`exec_server {execCase, handled}` for non-tool execs) and an unanswered exec sets `lastStreamEvent=exec_unanswered:<case>`. Previously exec messages were invisible in the lifecycle log — the blind spot behind unexplained mid-run stalls.
|
|
295
|
+
|
|
296
|
+
## [1.2.2] - 2026-07-23
|
|
297
|
+
|
|
298
|
+
### Fixed
|
|
299
|
+
|
|
300
|
+
- **Root hang:** Cursor `InteractionQuery` messages (web search, Exa, ask-question, switch-mode, create-plan, WebFetch field #9, unknown fields) are now always answered. Previously only WebFetch field #9 was handled — any other permission/query left the AgentService stream parked forever ("stops after a few minutes").
|
|
301
|
+
- Always-on lifecycle log at `$TMPDIR/pi-cursor-lifecycle.jsonl` (override with `PI_CURSOR_LIFECYCLE_LOG`) for stream start/close and interaction handling.
|
|
302
|
+
- h2-bridge: HTTP/2 PING every 20s to prevent intermediary idle GOAWAY; stderr/errors are surfaced instead of swallowed.
|
|
303
|
+
- Parent bridge now captures child stderr; heartbeats stay referenced during long tool pauses.
|
|
304
|
+
- Treat `heartbeat` / tool-call start / thinking-completed / summary updates as stream progress.
|
|
305
|
+
|
|
306
|
+
## [1.2.1] - 2026-07-23
|
|
307
|
+
|
|
308
|
+
### Fixed
|
|
309
|
+
|
|
310
|
+
- Stream idle watchdog no longer treats long pure-reasoning turns as dead: `tokenDelta`, handled native-tool reject round-trips, and `toolCallCompleted` now count as progress.
|
|
311
|
+
- **Idle timeouts and silent retries are disabled by default** (`PI_CURSOR_STREAM_IDLE_TIMEOUT_MS=0`, `PI_CURSOR_RESUME_IDLE_TIMEOUT_MS=0`, `PI_CURSOR_STREAM_IDLE_MAX_RETRIES=0`, `PI_CURSOR_H2_IDLE_TIMEOUT_MS=0`) so agent turns can run as long as Cursor keeps the stream open. Re-enable via env if you want a safety net.
|
|
312
|
+
- h2-bridge activity kill is off by default and configurable (`PI_CURSOR_H2_*_TIMEOUT_MS`); parent heartbeats still reset it when enabled.
|
|
313
|
+
- Blind idle retries (when re-enabled) are skipped if partial text/thinking was already streamed (avoids duplicated/jumbled answers).
|
|
314
|
+
- Idle retries force-refresh access tokens when a token provider is available.
|
|
315
|
+
- Conversation blob stores are soft-capped (~128 MiB) to limit long-session memory growth.
|
|
316
|
+
- Tool result `isError` is propagated into Cursor MCP results.
|
|
317
|
+
- Context-mode side-channel detection covers additional compaction / `[context]` injections.
|
|
318
|
+
|
|
319
|
+
### Added
|
|
320
|
+
|
|
321
|
+
- `/cursor.doctor` surfaces `lastStreamEvent`, last idle timeout metadata, and configured idle timeouts.
|
|
322
|
+
- Documented stream/bridge idle env vars in README.
|
|
323
|
+
- Unit coverage for idle progress classification, blind-restart gating, blob trimming, and timeout resolvers.
|
|
324
|
+
|
|
325
|
+
## [1.2.0] - 2026-07-23
|
|
326
|
+
|
|
327
|
+
### Changed
|
|
328
|
+
|
|
329
|
+
- Package now ships a bundled, minified `dist/` build (via `tsup`) instead of raw TypeScript source. Unpacked package size dropped ~818 KB → ~222 KB (packed ~154 KB → ~69 KB) by tree-shaking the generated protobuf module (~1000 exports, ~70 used). `main` and `pi.extensions` now point at `./dist/index.js`.
|
|
330
|
+
- `prepare` script builds `dist/` on install, so `git:`-based installs work without a committed build.
|
|
331
|
+
|
|
332
|
+
### Fixed
|
|
333
|
+
|
|
334
|
+
- Streaming hot path: the thinking-tag filter regex is compiled once at module load instead of being rebuilt on every streamed chunk.
|
|
335
|
+
|
|
336
|
+
## [1.1.0] - 2026-07-23
|
|
337
|
+
|
|
338
|
+
### Added
|
|
339
|
+
|
|
340
|
+
- Modular stream surface: `config`, `model-routing`, `context-normalize`, `recovery`, `protocol` extracted from the native runtime.
|
|
341
|
+
- Vitest unit suite covering recovery, model routing, context-mode normalize, consent, protocol framing, and usage formatting.
|
|
342
|
+
- Mid-session token re-resolution when access tokens near expiry (all credential sources).
|
|
343
|
+
- System credential consent opt-out via `PI_CURSOR_SYSTEM_CREDENTIALS=0`.
|
|
344
|
+
- `/cursor.doctor` fields: `clientVersion`, `systemCredentials`, `lastRecoverySkipReason`, protocol/auth hints.
|
|
345
|
+
- Protocol mismatch / auth error message enhancement with actionable hints.
|
|
346
|
+
|
|
347
|
+
### Changed
|
|
348
|
+
|
|
349
|
+
- Tool-continuation recovery prefers full-history rebuild when checkpoints are stale or tool-id mismatched (hard skip only when rebuild is unsafe).
|
|
350
|
+
- OpenAI-compatible local proxy path quarantined (not part of the public `src/stream` export surface).
|
|
351
|
+
- Agent URL resolution validates hosts via the existing allowlist helper.
|
|
352
|
+
- `SECURITY.md` updated for 1.x support and system-credential policy.
|
|
353
|
+
|
|
354
|
+
## [1.0.0] - 2026-07-23
|
|
355
|
+
|
|
356
|
+
### Added
|
|
357
|
+
|
|
358
|
+
- Initial stable release of `@rahularya01/pi-cursor` provider for Pi Coding Agent.
|
|
359
|
+
- 4-tier authentication resolution cascade: automatically resolves tokens from `CURSOR_ACCESS_TOKEN` env var, macOS Keychain (Cursor CLI), Cursor IDE local state (`state.vscdb`), and Pi OAuth store (`~/.pi/agent/auth.json`).
|
|
360
|
+
- Automatic WSL (Windows Subsystem for Linux) host Windows AppData credential auto-discovery.
|
|
361
|
+
- Deep-link PKCE browser OAuth (`/login cursor`) with token refresh.
|
|
362
|
+
- Native `streamSimple` transport over Connect/protobuf HTTP/2 via `h2-bridge.mjs`.
|
|
363
|
+
- Live model discovery (`GetUsableModels` + parameterized metadata) with static fallback catalog.
|
|
364
|
+
- Effort-suffix model collapse and Pi thinking-level routing.
|
|
365
|
+
- Context-mode normalization: side-channel user messages (such as context-mode routing or post-compaction `<session_state>` blocks) are safely normalized into the system prompt so Cursor models stay focused on the user's task.
|
|
366
|
+
- Visual TUI usage dashboard (`/cursor.usage`) with progress bars, plan breakdown (`Included`, `Auto`, `API`), reset dates, and dashboard link.
|
|
367
|
+
- Sanitized provider diagnostics command (`/cursor.doctor`) and model catalog command (`/cursor.models`).
|
|
368
|
+
- GitHub Actions CI/CD workflows targeting Node 22 and 24 for automated testing and npm publishing.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Upstream source
|
|
2
|
+
|
|
3
|
+
This package is a standalone full-source fork of `@rahularya01/pi-cursor`.
|
|
4
|
+
|
|
5
|
+
- Repository: https://github.com/Rahularya01/pi-cursor
|
|
6
|
+
- Tag: `v1.4.25`
|
|
7
|
+
- Commit: `5f8e775279f5e41cdd06791a036be4c7141097c3`
|
|
8
|
+
- Upstream npm package: `@rahularya01/pi-cursor@1.4.25`
|
|
9
|
+
- License: MIT
|
|
10
|
+
|
|
11
|
+
The production source, generated protobuf bindings, protocol schema, build tooling, tests, smoke scripts, and upstream protocol notes were copied from that revision. Upstream release history is preserved as [`UPSTREAM_CHANGELOG.md`](./UPSTREAM_CHANGELOG.md).
|
|
12
|
+
|
|
13
|
+
## Local differences
|
|
14
|
+
|
|
15
|
+
- Published independently as the unscoped `pi-provider-cursor-ask` package; it is not embedded in the repository's root bundle.
|
|
16
|
+
- Keeps the upstream `cursor` provider/login identity and `cursor-native` stream API so existing Pi credentials continue to work. OAuth label is `Cursor Ask`, and diagnostics stay `/cursor` subcommands.
|
|
17
|
+
- Declares `apiKey: "$CURSOR_ACCESS_TOKEN"` on `registerProvider` so Pi will list models when that env var is set (CI smoke). Ask still resolves the token itself; upstream relies on OAuth only at this layer.
|
|
18
|
+
- Filters the processed Cursor catalog in `src/models/ask-catalog.ts` to a curated subset: 1M Claude rows, Composer 2.5 / Composer 2.5 Fast, and passthrough Grok 4.6 / Fast rows when the live catalog contains them. Other families are not registered; upstream `processModels` remains unchanged.
|
|
19
|
+
- Keeps thinking enabled for Claude rows and maps supported Pi levels to explicit Cursor `requestedModelId` plus `thinking`, `context`, `effort`, and `fast` parameters. Composer 2.5 maps Pi `off`/`max` to Cursor Max Mode instead of inventing an effort parameter.
|
|
20
|
+
- Accepts both current folded Claude ids and legacy bundled-catalog spellings such as `claude-4.6-opus-thinking`.
|
|
21
|
+
- Replaces the upstream user README and changelog with fork-specific bilingual usage documentation and release history.
|
|
22
|
+
|
|
23
|
+
Future upstream updates are reviewed and merged into this package explicitly rather than inherited through a runtime dependency.
|