pi-clinepass 0.1.1 → 0.1.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.
- package/CHANGELOG.md +17 -0
- package/README.md +8 -3
- package/package.json +4 -3
- package/src/auth.ts +30 -18
- package/src/calibrate.ts +773 -0
- package/src/catalog.ts +21 -18
- package/src/errors.ts +9 -7
- package/src/headers.ts +16 -13
- package/src/index.ts +322 -109
- package/src/pricing.ts +204 -0
- package/src/settings.ts +17 -10
- package/src/thinking.ts +104 -0
- package/src/usage.ts +201 -49
- package/src/views.ts +397 -0
- package/src/workos.ts +18 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 0.1.3 - 2026-08-31
|
|
6
|
+
|
|
7
|
+
- Corrected model input modalities: `glm-5.3` and `deepseek-v4-flash` are text-only, `mimo-v2.5` and `qwen3.8-max` accept images
|
|
8
|
+
|
|
9
|
+
## 0.1.2 - 2026-08-30
|
|
10
|
+
|
|
11
|
+
- New paid model: `cline-pass/glm-5.3-flash` ($0.15/$0.50/$0.03)
|
|
12
|
+
- New free model: `cline-free/longcat-2.0`
|
|
13
|
+
- Model picker shows prices
|
|
14
|
+
- Price calibration via `/clinepass` measures real billing and updates the whole panel; fatal errors abort the run
|
|
15
|
+
- `/clinepass` runs in a centered modal: dashboard (prices, plan sidebar) and calibration (live per-model progress, esc-esc cancel)
|
|
16
|
+
- Prices stored in `clinepass-prices.json`, seeded on install, synced per release
|
|
17
|
+
- Gateway thinking-stream corruption repaired
|
|
18
|
+
- pi's built-in cost estimate off for ClinePass (the footer meter is the single cost display, turn cost includes every tool-calling round)
|
|
19
|
+
- Free-route headers applied to every free model
|
|
20
|
+
- 403 on free routes classified as route gate, not subscription
|
|
21
|
+
|
|
5
22
|
## 0.1.1 - 2026-08-27
|
|
6
23
|
|
|
7
24
|
- Catalog: `stealth/ox-alpha` is now `z-ai/glm-5.3-flash` (renamed)
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# pi-clinepass
|
|
4
4
|
|
|
5
|
-
**ClinePass
|
|
5
|
+
**ClinePass for [pi](https://pi.dev) coding agent**
|
|
6
6
|
|
|
7
7
|
Dollar-based limits, live cost tracking, and plan cap reporting.
|
|
8
8
|
|
|
@@ -25,9 +25,10 @@ Dollar-based limits, live cost tracking, and plan cap reporting.
|
|
|
25
25
|
|
|
26
26
|
## Highlights
|
|
27
27
|
|
|
28
|
-
- **
|
|
28
|
+
- **18 Models**: 14 ClinePass models on a dollar-based limit system plus 4 free tier models
|
|
29
29
|
- **Live Status Meter**: Per-turn and session cost directly in the pi footer
|
|
30
30
|
- **Plan Utilization**: 5-hour, weekly, and monthly caps tracked via `/clinepass`
|
|
31
|
+
- **Price Calibration**: measure real gateway billing from `/clinepass` to keep displayed prices honest
|
|
31
32
|
- **Simple Auth**: One-time login via Cline CLI, browser, or API key
|
|
32
33
|
|
|
33
34
|
---
|
|
@@ -68,7 +69,7 @@ Select **ClinePass** to choose your sign-in method:
|
|
|
68
69
|
|
|
69
70
|
### 2. Select a Model
|
|
70
71
|
|
|
71
|
-
Pick any model using the interactive selector:
|
|
72
|
+
Pick any model using the interactive selector — prices are shown right in the picker:
|
|
72
73
|
|
|
73
74
|
```
|
|
74
75
|
/model
|
|
@@ -84,6 +85,10 @@ View the live rate sheet and plan limit utilization anytime:
|
|
|
84
85
|
/clinepass
|
|
85
86
|
```
|
|
86
87
|
|
|
88
|
+
The command opens a menu: the dashboard shows model rates and plan utilization
|
|
89
|
+
in a centered modal, or run **price calibration** to measure real gateway
|
|
90
|
+
billing and update the whole panel (uses ~5-10% of the 5-hour quota).
|
|
91
|
+
|
|
87
92
|
<div align="center">
|
|
88
93
|
<img src="https://raw.githubusercontent.com/fifidayone/pi-clinepass/main/assets/report.png" alt="ClinePass report with pricing and plan limits" width="620">
|
|
89
94
|
</div>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-clinepass",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "ClinePass
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "ClinePass for pi — static measured-price catalog, server-truth billing meter, free models",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
7
7
|
"cline",
|
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@earendil-works/pi-ai": "*",
|
|
40
|
-
"@earendil-works/pi-coding-agent": "*"
|
|
40
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
41
|
+
"@earendil-works/pi-tui": "*"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
44
|
"@types/node": "^26.3.0",
|
package/src/auth.ts
CHANGED
|
@@ -178,7 +178,10 @@ export function resolvePiStoredCredential(options: AuthOptions = {}): ClineAuthC
|
|
|
178
178
|
* produced rotated tokens — if the server rotates single-use refresh
|
|
179
179
|
* tokens, discarding the new one would leave pi's stored credential dead
|
|
180
180
|
* and force a re-login. Waits for pi's lock file (`<auth.json>.lock`, held
|
|
181
|
-
* by proper-lockfile while pi writes) to clear before merging
|
|
181
|
+
* by proper-lockfile while pi writes) to clear before merging, then verifies
|
|
182
|
+
* after writing: the meter refresh and pi's own chat-path refresh can fire at
|
|
183
|
+
* the same near-expiry moment, so if pi rewrote the file in between, the
|
|
184
|
+
* merge is redone once on top of the newer content instead of dropping it.
|
|
182
185
|
*/
|
|
183
186
|
export async function persistOAuthCredential(
|
|
184
187
|
credential: OAuthCredentials,
|
|
@@ -187,26 +190,35 @@ export async function persistOAuthCredential(
|
|
|
187
190
|
const { homeDir, readFile, fileExists, writeFile } = resolveOptions(options);
|
|
188
191
|
const authPath = join(homeDir(), ".pi", "agent", "auth.json");
|
|
189
192
|
const lockPath = `${authPath}.lock`;
|
|
193
|
+
const entry = {
|
|
194
|
+
type: "oauth",
|
|
195
|
+
access: credential.access,
|
|
196
|
+
refresh: credential.refresh,
|
|
197
|
+
expires: credential.expires,
|
|
198
|
+
};
|
|
190
199
|
|
|
191
|
-
for (let
|
|
192
|
-
|
|
193
|
-
|
|
200
|
+
for (let pass = 0; pass < 2; pass++) {
|
|
201
|
+
for (let attempt = 0; attempt < 20 && fileExists(lockPath); attempt++) {
|
|
202
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const current = fileExists(authPath) ? readFile(authPath) : "{}";
|
|
206
|
+
const parsed: unknown = current.trim() ? JSON.parse(current) : {};
|
|
207
|
+
if (!isRecord(parsed)) {
|
|
208
|
+
throw new Error("auth.json is not a JSON object");
|
|
209
|
+
}
|
|
210
|
+
const serialized = JSON.stringify({ ...parsed, clinepass: entry }, null, 2);
|
|
211
|
+
writeFile(authPath, serialized);
|
|
194
212
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
213
|
+
let contended = false;
|
|
214
|
+
for (let attempt = 0; attempt < 20 && fileExists(lockPath); attempt++) {
|
|
215
|
+
contended = true;
|
|
216
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
217
|
+
}
|
|
218
|
+
// Done only when pi never contended and the file still holds exactly what
|
|
219
|
+
// we wrote; otherwise loop once more and merge over the newer content.
|
|
220
|
+
if (!contended && (!fileExists(authPath) || readFile(authPath) === serialized)) return;
|
|
199
221
|
}
|
|
200
|
-
const next = {
|
|
201
|
-
...parsed,
|
|
202
|
-
clinepass: {
|
|
203
|
-
type: "oauth",
|
|
204
|
-
access: credential.access,
|
|
205
|
-
refresh: credential.refresh,
|
|
206
|
-
expires: credential.expires,
|
|
207
|
-
},
|
|
208
|
-
};
|
|
209
|
-
writeFile(authPath, JSON.stringify(next, null, 2));
|
|
210
222
|
}
|
|
211
223
|
|
|
212
224
|
// ─── Login chain ──────────────────────────────────────────────────────────
|