pi-cockpit 0.24.4 → 0.24.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/package.json CHANGED
@@ -1,88 +1,88 @@
1
- {
2
- "name": "pi-cockpit",
3
- "version": "0.24.4",
4
- "description": "Responsive Maestro operations sidebar, fallback status widgets, and footer for Pi.",
5
- "type": "module",
6
- "engines": {
7
- "node": ">=22.19.0"
8
- },
9
- "keywords": [
10
- "pi-package",
11
- "pi",
12
- "pi-extension",
13
- "tui",
14
- "teammate",
15
- "todo"
16
- ],
17
- "license": "MIT",
18
- "files": [
19
- "src/",
20
- "themes/",
21
- "README.md"
22
- ],
23
- "scripts": {
24
- "test": "node --test --experimental-transform-types tests/config.test.ts tests/public-events.test.ts tests/ui-ownership-runtime.test.ts tests/maestro-store.test.ts tests/split-pane.test.ts tests/editor-bottom.test.ts tests/sidebar-render.test.ts tests/sidebar-controller.test.ts tests/viewport-stability.test.ts tests/terminal-emulator.test.ts tests/compaction-style.test.ts tests/quiet-tools.test.ts tests/native-host.test.ts tests/native-host-entry.test.ts tests/native-host-quiet.test.ts tests/edit-guard.test.ts tests/agents-store.test.ts tests/endpoint-store.test.ts tests/session-ui-state.test.ts tests/session-tabs.test.ts tests/agent-bar.test.ts tests/supervision-store.test.ts tests/bash-bg-store.test.ts tests/bash-bg-widget.test.ts tests/bash-bg-overlay.test.ts tests/todo-overlay.test.ts tests/agent-overlay.test.ts tests/todo-store.test.ts tests/render.test.ts tests/agent-scroll.test.ts tests/session-bar.test.ts tests/session-detail.test.ts tests/footer.test.ts tests/extension-status.test.ts tests/teammate-message.test.ts tests/input-routing.test.ts tests/input-history-store.test.ts tests/unified-editor.test.ts tests/integration-contract.test.ts tests/stack-widget.test.ts tests/zen-render.test.ts tests/zen-browse.test.ts tests/zen-sheet.test.ts tests/settings-view.test.ts tests/thinking-fold.test.ts tests/thinking-timer.test.ts tests/tick-policy.test.ts tests/ambient.test.ts tests/viewport.test.ts tests/theme-picker.test.ts tests/model-picker.test.ts tests/title-gen.test.ts tests/title-llm.test.ts tests/settings-registry.test.ts tests/settings-coordinator.test.ts tests/settings-locale.test.ts tests/tui-i18n.test.ts tests/settings-shell.test.ts tests/settings-cockpit-provider.test.ts tests/settings-cross-package.test.ts tests/ui-primitives.test.ts tests/settings-shell-secret.test.ts tests/settings-shell-listcrud.test.ts tests/capturing-overlay.test.ts tests/claude-editor.test.ts tests/fullscreen-controller.test.ts tests/transcript-selection.test.ts tests/terminal-cleanup.test.ts tests/terminal-capability.test.ts tests/usage-core.test.ts tests/usage-extension.test.ts tests/usage-history.test.ts tests/usage-sparkline.test.ts tests/patch-health.test.ts",
25
- "typecheck": "tsc --noEmit",
26
- "prepack": "node ../../scripts/bundle-settings-core.mjs",
27
- "postpack": "node ../../scripts/bundle-settings-core.mjs --clean"
28
- },
29
- "pi": {
30
- "extensions": [
31
- "./src/extension/index.ts"
32
- ],
33
- "themes": [
34
- "./themes"
35
- ]
36
- },
37
- "dependencies": {
38
- "pi-maestro-settings-core": "0.2.3",
39
- "proper-lockfile": "4.1.2"
40
- },
41
- "bundledDependencies": [
42
- "pi-maestro-settings-core"
43
- ],
44
- "peerDependencies": {
45
- "@earendil-works/pi-agent-core": "*",
46
- "@earendil-works/pi-ai": "*",
47
- "@earendil-works/pi-coding-agent": "*",
48
- "@earendil-works/pi-tui": "*",
49
- "pi-maestro-teammate": "^2.8.1",
50
- "typebox": "*"
51
- },
52
- "peerDependenciesMeta": {
53
- "@earendil-works/pi-agent-core": {
54
- "optional": true
55
- },
56
- "@earendil-works/pi-ai": {
57
- "optional": true
58
- },
59
- "@earendil-works/pi-coding-agent": {
60
- "optional": true
61
- },
62
- "@earendil-works/pi-tui": {
63
- "optional": true
64
- },
65
- "pi-maestro-teammate": {
66
- "optional": true
67
- },
68
- "typebox": {
69
- "optional": true
70
- }
71
- },
72
- "devDependencies": {
73
- "@earendil-works/pi-agent-core": "0.99.0",
74
- "@earendil-works/pi-ai": "0.99.0",
75
- "@earendil-works/pi-coding-agent": "0.99.0",
76
- "@earendil-works/pi-tui": "0.99.0",
77
- "@types/node": "^22.0.0",
78
- "pi-maestro-teammate": "2.8.1",
79
- "typebox": "1.3.27",
80
- "typescript": "^5.5.0"
81
- },
82
- "main": "./src/index.ts",
83
- "exports": {
84
- ".": "./src/index.ts",
85
- "./v1/events": "./src/public/v1/events.ts",
86
- "./src/*": "./src/*"
87
- }
88
- }
1
+ {
2
+ "name": "pi-cockpit",
3
+ "version": "0.24.5",
4
+ "description": "Responsive Maestro operations sidebar, fallback status widgets, and footer for Pi.",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=22.19.0"
8
+ },
9
+ "keywords": [
10
+ "pi-package",
11
+ "pi",
12
+ "pi-extension",
13
+ "tui",
14
+ "teammate",
15
+ "todo"
16
+ ],
17
+ "license": "MIT",
18
+ "files": [
19
+ "src/",
20
+ "themes/",
21
+ "README.md"
22
+ ],
23
+ "scripts": {
24
+ "test": "node --test --experimental-transform-types tests/config.test.ts tests/public-events.test.ts tests/ui-ownership-runtime.test.ts tests/maestro-store.test.ts tests/split-pane.test.ts tests/editor-bottom.test.ts tests/sidebar-render.test.ts tests/sidebar-controller.test.ts tests/viewport-stability.test.ts tests/terminal-emulator.test.ts tests/compaction-style.test.ts tests/quiet-tools.test.ts tests/native-host.test.ts tests/native-host-entry.test.ts tests/native-host-quiet.test.ts tests/edit-guard.test.ts tests/agents-store.test.ts tests/endpoint-store.test.ts tests/session-ui-state.test.ts tests/session-tabs.test.ts tests/agent-bar.test.ts tests/supervision-store.test.ts tests/bash-bg-store.test.ts tests/bash-bg-widget.test.ts tests/bash-bg-overlay.test.ts tests/todo-overlay.test.ts tests/agent-overlay.test.ts tests/todo-store.test.ts tests/render.test.ts tests/agent-scroll.test.ts tests/session-bar.test.ts tests/session-detail.test.ts tests/footer.test.ts tests/extension-status.test.ts tests/teammate-message.test.ts tests/input-routing.test.ts tests/input-history-store.test.ts tests/unified-editor.test.ts tests/integration-contract.test.ts tests/stack-widget.test.ts tests/zen-render.test.ts tests/zen-browse.test.ts tests/zen-sheet.test.ts tests/settings-view.test.ts tests/thinking-fold.test.ts tests/thinking-timer.test.ts tests/tick-policy.test.ts tests/ambient.test.ts tests/viewport.test.ts tests/theme-picker.test.ts tests/model-picker.test.ts tests/title-gen.test.ts tests/title-llm.test.ts tests/settings-registry.test.ts tests/settings-coordinator.test.ts tests/settings-locale.test.ts tests/tui-i18n.test.ts tests/settings-shell.test.ts tests/settings-cockpit-provider.test.ts tests/settings-cross-package.test.ts tests/ui-primitives.test.ts tests/settings-shell-secret.test.ts tests/settings-shell-listcrud.test.ts tests/capturing-overlay.test.ts tests/claude-editor.test.ts tests/fullscreen-controller.test.ts tests/transcript-selection.test.ts tests/terminal-cleanup.test.ts tests/terminal-capability.test.ts tests/usage-core.test.ts tests/usage-extension.test.ts tests/usage-history.test.ts tests/usage-sparkline.test.ts tests/patch-health.test.ts",
25
+ "typecheck": "tsc --noEmit",
26
+ "prepack": "node ../../scripts/bundle-settings-core.mjs",
27
+ "postpack": "node ../../scripts/bundle-settings-core.mjs --clean"
28
+ },
29
+ "pi": {
30
+ "extensions": [
31
+ "./src/extension/index.ts"
32
+ ],
33
+ "themes": [
34
+ "./themes"
35
+ ]
36
+ },
37
+ "dependencies": {
38
+ "pi-maestro-settings-core": "0.2.3",
39
+ "proper-lockfile": "4.1.2"
40
+ },
41
+ "bundledDependencies": [
42
+ "pi-maestro-settings-core"
43
+ ],
44
+ "peerDependencies": {
45
+ "@earendil-works/pi-agent-core": "*",
46
+ "@earendil-works/pi-ai": "*",
47
+ "@earendil-works/pi-coding-agent": "*",
48
+ "@earendil-works/pi-tui": "*",
49
+ "pi-maestro-teammate": "^2.8.1",
50
+ "typebox": "*"
51
+ },
52
+ "peerDependenciesMeta": {
53
+ "@earendil-works/pi-agent-core": {
54
+ "optional": true
55
+ },
56
+ "@earendil-works/pi-ai": {
57
+ "optional": true
58
+ },
59
+ "@earendil-works/pi-coding-agent": {
60
+ "optional": true
61
+ },
62
+ "@earendil-works/pi-tui": {
63
+ "optional": true
64
+ },
65
+ "pi-maestro-teammate": {
66
+ "optional": true
67
+ },
68
+ "typebox": {
69
+ "optional": true
70
+ }
71
+ },
72
+ "devDependencies": {
73
+ "@earendil-works/pi-agent-core": "0.99.0",
74
+ "@earendil-works/pi-ai": "0.99.0",
75
+ "@earendil-works/pi-coding-agent": "0.99.0",
76
+ "@earendil-works/pi-tui": "0.99.0",
77
+ "@types/node": "^22.0.0",
78
+ "pi-maestro-teammate": "2.10.1",
79
+ "typebox": "1.3.27",
80
+ "typescript": "^5.5.0"
81
+ },
82
+ "main": "./src/index.ts",
83
+ "exports": {
84
+ ".": "./src/index.ts",
85
+ "./v1/events": "./src/public/v1/events.ts",
86
+ "./src/*": "./src/*"
87
+ }
88
+ }
package/src/usage/core.ts CHANGED
@@ -3,6 +3,7 @@ import * as os from "node:os";
3
3
  import * as path from "node:path";
4
4
 
5
5
  export type ProviderKey =
6
+ | "chatgpt"
6
7
  | "codex"
7
8
  | "claude"
8
9
  | "zai"
@@ -15,6 +16,7 @@ export type ProviderKey =
15
16
  | "moonshot"
16
17
  | "moonshot-cn";
17
18
  export type PiProviderId =
19
+ | "openai"
18
20
  | "openai-codex"
19
21
  | "anthropic"
20
22
  | "zai"
@@ -570,6 +572,16 @@ function readCodexAccountId(token: string): string | undefined {
570
572
  }
571
573
  }
572
574
 
575
+ export function getChatGPTUsage(): UsageData {
576
+ // Pi's direct-login grant is not a Codex/WHAM credential.
577
+ return {
578
+ session: 0,
579
+ weekly: 0,
580
+ quotaHidden: true,
581
+ notice: "Subscription quota is not exposed by Pi; check https://chatgpt.com/settings/usage",
582
+ };
583
+ }
584
+
573
585
  export async function fetchCodexUsage(token: string, config: RequestConfig = {}): Promise<UsageData> {
574
586
  const headers: Record<string, string> = { Authorization: `Bearer ${token}` };
575
587
  // Without account routing, WHAM can return a different account's quota.
@@ -1183,6 +1195,7 @@ export function detectProvider(
1183
1195
  ): ProviderKey | null {
1184
1196
  if (!model || typeof model === "string") return null;
1185
1197
  switch ((model.provider || "").toLowerCase()) {
1198
+ case "openai": return "chatgpt";
1186
1199
  case "openai-codex": return "codex";
1187
1200
  case "anthropic": return "claude";
1188
1201
  case "zai": return "zai";
@@ -1200,6 +1213,7 @@ export function detectProvider(
1200
1213
 
1201
1214
  export function providerToPiProviderId(provider: ProviderKey): PiProviderId {
1202
1215
  switch (provider) {
1216
+ case "chatgpt": return "openai";
1203
1217
  case "codex": return "openai-codex";
1204
1218
  case "claude": return "anthropic";
1205
1219
  case "zai": return "zai";
@@ -1231,6 +1245,7 @@ export async function fetchAllUsages(
1231
1245
  ): Promise<UsageByProvider> {
1232
1246
  const endpoints = config.endpoints ?? resolveUsageEndpoints(config.env);
1233
1247
  const results: UsageByProvider = {
1248
+ chatgpt: null,
1234
1249
  codex: null,
1235
1250
  claude: null,
1236
1251
  zai: null,
@@ -1253,6 +1268,7 @@ export async function fetchAllUsages(
1253
1268
  }));
1254
1269
  };
1255
1270
 
1271
+ if (tokens.chatgpt) results.chatgpt = getChatGPTUsage();
1256
1272
  if (tokens.codex) assign("codex", fetchCodexUsage(tokens.codex, config));
1257
1273
  if (tokens.claude) {
1258
1274
  assign("claude", fetchClaudeUsageWithFallback(tokens.claude, {
@@ -44,6 +44,7 @@ import {
44
44
  fetchAllUsages,
45
45
  fetchClaudeUsageWithFallback,
46
46
  fetchCodexUsage,
47
+ getChatGPTUsage,
47
48
  fetchDeepSeekBalance,
48
49
  fetchKimiUsage,
49
50
  fetchMiniMaxUsage,
@@ -65,6 +66,7 @@ import { type CockpitConfig, DEFAULT_CONFIG } from "../types.ts";
65
66
  const EXTENSION_ID = "pi-cockpit:usage-bars";
66
67
  const USAGE_UPDATE_EVENT = `${EXTENSION_ID}:update`;
67
68
  const PROVIDERS: readonly ProviderKey[] = [
69
+ "chatgpt",
68
70
  "codex",
69
71
  "claude",
70
72
  "zai",
@@ -79,6 +81,7 @@ const PROVIDERS: readonly ProviderKey[] = [
79
81
  ];
80
82
 
81
83
  const PROVIDER_LABELS: Record<ProviderKey, string> = {
84
+ chatgpt: "ChatGPT (official)",
82
85
  codex: "Codex",
83
86
  claude: "Claude",
84
87
  zai: "ZAI Coding Plan (Global)",
@@ -624,6 +627,7 @@ export function createUsageSubsystem(options: CreateUsageSubsystemOptions): Usag
624
627
 
625
628
  const endpoints = resolveUsageEndpoints();
626
629
  const state: UsageState = {
630
+ chatgpt: null,
627
631
  codex: null,
628
632
  claude: null,
629
633
  zai: null,
@@ -731,7 +735,7 @@ export function createUsageSubsystem(options: CreateUsageSubsystemOptions): Usag
731
735
  return false;
732
736
  }
733
737
 
734
- function isClaudeSubscriptionAuth(source: string | undefined): boolean {
738
+ function isSubscriptionAuth(source: string | undefined): boolean {
735
739
  // Pi 0.84 exposes AuthResult.source as a human-readable label rather than a
736
740
  // credential-type discriminator. Keep the compatibility assumption in one
737
741
  // place until ModelRegistry exposes the resolved credential type directly.
@@ -746,7 +750,7 @@ export function createUsageSubsystem(options: CreateUsageSubsystemOptions): Usag
746
750
 
747
751
  try {
748
752
  const resolved = await ctx.modelRegistry.getProviderAuth(providerId);
749
- if (provider === "claude" && !isClaudeSubscriptionAuth(resolved?.source)) return {};
753
+ if ((provider === "claude" || provider === "chatgpt") && !isSubscriptionAuth(resolved?.source)) return {};
750
754
  const token = resolved?.auth.apiKey;
751
755
  if (token) return { token };
752
756
  // Some OAuth flows (e.g. kimi-coding) expose the token only as a Bearer
@@ -778,6 +782,7 @@ export function createUsageSubsystem(options: CreateUsageSubsystemOptions): Usag
778
782
  return;
779
783
  }
780
784
 
785
+ if (provider === "chatgpt") state.chatgpt = getChatGPTUsage();
781
786
  if (provider === "codex") state.codex = await fetchCodexUsage(credential.token, { signal });
782
787
  if (provider === "claude") state.claude = await fetchClaudeUsageWithFallback(credential.token, { signal });
783
788
  if (provider === "zai") state.zai = await fetchZaiUsage(credential.token, "zai", { endpoints, signal });
@@ -886,6 +891,20 @@ export function createUsageSubsystem(options: CreateUsageSubsystemOptions): Usag
886
891
  pollTimer.unref?.();
887
892
  }
888
893
 
894
+ const unsubscribeAccountChanged = pi.events.on("pi:account-changed", (payload: unknown) => {
895
+ if (!payload || typeof payload !== "object" || !("providerId" in payload) ||
896
+ typeof payload.providerId !== "string") return;
897
+ const provider = detectProvider({ provider: payload.providerId });
898
+ if (!provider) return;
899
+ state[provider] = null;
900
+ delete state.available[provider];
901
+ if (provider === state.activeProvider) {
902
+ providerPollController?.abort();
903
+ onStatusChange();
904
+ if (!isManualRefresh()) void poll();
905
+ }
906
+ });
907
+
889
908
  return {
890
909
  async start(ctx) {
891
910
  currentContext = ctx;
@@ -983,6 +1002,7 @@ export function createUsageSubsystem(options: CreateUsageSubsystemOptions): Usag
983
1002
  },
984
1003
 
985
1004
  dispose() {
1005
+ unsubscribeAccountChanged();
986
1006
  providerPollController?.abort();
987
1007
  providerPollController = undefined;
988
1008
  sessionController?.abort();