@tokentop/ttop 0.4.0 → 0.5.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.
Files changed (75) hide show
  1. package/package.json +9 -4
  2. package/src/agents/aggregator.ts +8 -1
  3. package/src/agents/types.ts +3 -0
  4. package/src/cli.ts +2 -2
  5. package/src/demo/simulator.ts +1 -1
  6. package/src/plugins/agents/index.ts +2 -0
  7. package/src/plugins/auth-sources.ts +2 -3
  8. package/src/plugins/lifecycle.ts +1 -1
  9. package/src/plugins/loader.test.ts +1 -1
  10. package/src/plugins/loader.ts +15 -7
  11. package/src/plugins/notification-bus.ts +5 -2
  12. package/src/plugins/notifications/terminal-bell.ts +1 -1
  13. package/src/plugins/notifications/visual-flash.ts +1 -1
  14. package/src/plugins/plugin-context-factory.ts +4 -19
  15. package/src/plugins/providers/anthropic.ts +2 -2
  16. package/src/plugins/providers/antigravity.ts +1 -1
  17. package/src/plugins/providers/chutes.ts +189 -0
  18. package/src/plugins/providers/codex.ts +1 -1
  19. package/src/plugins/providers/gemini.ts +1 -1
  20. package/src/plugins/providers/github-copilot.ts +1 -1
  21. package/src/plugins/providers/index.ts +1 -0
  22. package/src/plugins/providers/minimax.ts +1 -1
  23. package/src/plugins/providers/openai-api.ts +1 -1
  24. package/src/plugins/providers/opencode-zen.ts +1 -1
  25. package/src/plugins/providers/perplexity.ts +1 -1
  26. package/src/plugins/providers/zai.ts +1 -1
  27. package/src/plugins/registry.ts +9 -9
  28. package/src/plugins/sandbox-guard.test.ts +1 -1
  29. package/src/plugins/sandbox-guard.ts +1 -1
  30. package/src/plugins/sandbox.ts +1 -1
  31. package/src/plugins/themes/catppuccin-latte.ts +1 -1
  32. package/src/plugins/themes/catppuccin-mocha.ts +1 -1
  33. package/src/plugins/themes/claude-code.ts +1 -1
  34. package/src/plugins/themes/dracula.ts +1 -1
  35. package/src/plugins/themes/github-light.ts +1 -1
  36. package/src/plugins/themes/gruvbox-dark.ts +1 -1
  37. package/src/plugins/themes/gruvbox-light.ts +1 -1
  38. package/src/plugins/themes/kanagawa.ts +1 -1
  39. package/src/plugins/themes/nord.ts +1 -1
  40. package/src/plugins/themes/one-dark.ts +1 -1
  41. package/src/plugins/themes/opencode.ts +1 -1
  42. package/src/plugins/themes/rose-pine-dawn.ts +1 -1
  43. package/src/plugins/themes/rose-pine.ts +1 -1
  44. package/src/plugins/themes/solarized-light.ts +1 -1
  45. package/src/plugins/themes/tokyo-night.ts +1 -1
  46. package/src/plugins/update-checker.ts +2 -2
  47. package/src/pricing/estimator.test.ts +1 -1
  48. package/src/pricing/estimator.ts +1 -1
  49. package/src/pricing/fallback.ts +1 -1
  50. package/src/pricing/index.ts +1 -1
  51. package/src/pricing/models-dev.ts +1 -1
  52. package/src/storage/index.ts +6 -0
  53. package/src/storage/migrations/index.ts +17 -0
  54. package/src/storage/repos/pluginStorage.ts +35 -0
  55. package/src/tui/App.tsx +1 -1
  56. package/src/tui/components/ProviderCard.tsx +1 -1
  57. package/src/tui/components/ProviderDetailPanel.tsx +1 -1
  58. package/src/tui/components/SessionDetailsDrawer.tsx +10 -0
  59. package/src/tui/components/SessionsTable.tsx +9 -2
  60. package/src/tui/components/SettingsModal.tsx +1 -1
  61. package/src/tui/components/ThemePicker.tsx +1 -1
  62. package/src/tui/contexts/AgentSessionContext.tsx +1 -1
  63. package/src/tui/contexts/PluginContext.tsx +8 -4
  64. package/src/tui/contexts/RealTimeActivityContext.tsx +33 -20
  65. package/src/tui/contexts/ThemeContext.tsx +3 -3
  66. package/src/tui/hooks/useSessionEnrichedProviders.ts +1 -1
  67. package/src/tui/views/SettingsView.tsx +1 -1
  68. package/src/version.ts +1 -1
  69. package/src/plugins/types/agent.ts +0 -108
  70. package/src/plugins/types/base.ts +0 -278
  71. package/src/plugins/types/index.ts +0 -19
  72. package/src/plugins/types/notification.ts +0 -51
  73. package/src/plugins/types/provider.ts +0 -237
  74. package/src/plugins/types/theme.ts +0 -78
  75. package/src/storage/database.ts +0 -623
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokentop/ttop",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Real-time AI token usage monitor - htop for your API costs",
5
5
  "author": "Nigel Bazzeghin <nbazzeghin@gmail.com>",
6
6
  "license": "MIT",
@@ -33,11 +33,13 @@
33
33
  "snapshot": "bun src/tui/debug/snapshot.tsx"
34
34
  },
35
35
  "dependencies": {
36
- "@opentui/core": "0.1.81",
37
- "@opentui/react": "0.1.81",
36
+ "@opentui/core": "0.1.84",
37
+ "@opentui/react": "0.1.84",
38
38
  "@tokentop/agent-claude-code": "^1.1.0",
39
+ "@tokentop/agent-cursor": "^1.2.0",
39
40
  "@tokentop/agent-opencode": "^1.0.0",
40
- "@tokentop/plugin-sdk": "^1.1.0",
41
+ "@tokentop/agent-copilot-cli": "^1.0.0",
42
+ "@tokentop/plugin-sdk": "^1.3.0",
41
43
  "react": "^19.0.0",
42
44
  "react-devtools-core": "^7.0.1",
43
45
  "zod": "^4.0.0"
@@ -67,5 +69,8 @@
67
69
  },
68
70
  "engines": {
69
71
  "bun": ">=1.0.0"
72
+ },
73
+ "overrides": {
74
+ "@types/node": "^25.0.0"
70
75
  }
71
76
  }
@@ -1,4 +1,4 @@
1
- import type { SessionUsageData } from "@/plugins/types/agent.ts";
1
+ import type { SessionUsageData } from "@tokentop/plugin-sdk";
2
2
  import {
3
3
  type AgentId,
4
4
  type AgentName,
@@ -189,6 +189,13 @@ export function aggregateSessionUsage(options: AggregateOptions): AgentSessionAg
189
189
  };
190
190
  if (session.sessionName) aggregate.sessionName = session.sessionName;
191
191
  if (session.projectPath) aggregate.projectPath = session.projectPath;
192
+
193
+ // Propagate metadata — session is estimated if any row is estimated
194
+ const sessionRows = rows.filter((r) => r.sessionId === sessionId);
195
+ const anyEstimated = sessionRows.some((r) => (r.metadata?.isEstimated as boolean) === true);
196
+ if (anyEstimated) {
197
+ aggregate.metadata = { isEstimated: true };
198
+ }
192
199
  results.push(aggregate);
193
200
  }
194
201
 
@@ -60,6 +60,9 @@ export interface AgentSessionAggregate {
60
60
 
61
61
  /** @internal Keyed by `providerId::modelId`. Set by aggregator, consumed by costing. */
62
62
  _streamWindowedTokens?: Map<string, StreamWindowedTokens>;
63
+
64
+ /** Plugin-provided metadata merged from underlying SessionUsageData rows. */
65
+ metadata?: Record<string, unknown>;
63
66
  }
64
67
 
65
68
  export interface AgentInfo {
package/src/cli.ts CHANGED
@@ -114,7 +114,7 @@ async function main() {
114
114
  }
115
115
  const seedStr = commandArgs[++i];
116
116
  const seed = seedStr ? parseInt(seedStr, 10) : NaN;
117
- if (isNaN(seed)) {
117
+ if (Number.isNaN(seed)) {
118
118
  console.error("Error: --seed requires a number");
119
119
  process.exit(1);
120
120
  }
@@ -137,7 +137,7 @@ async function main() {
137
137
  if (arg === "-r" || arg === "--refresh") {
138
138
  const intervalStr = commandArgs[++i];
139
139
  const interval = intervalStr ? parseInt(intervalStr, 10) : NaN;
140
- if (isNaN(interval) || interval < 1000) {
140
+ if (Number.isNaN(interval) || interval < 1000) {
141
141
  console.error("Error: --refresh must be a number >= 1000");
142
142
  process.exit(1);
143
143
  }
@@ -1,5 +1,5 @@
1
+ import type { ProviderUsageData } from "@tokentop/plugin-sdk";
1
2
  import type { AgentSessionAggregate, AgentSessionStream } from "@/agents/types.ts";
2
- import type { ProviderUsageData } from "@/plugins/types/provider.ts";
3
3
  import type { UsageEventInsert } from "@/storage/types.ts";
4
4
 
5
5
  /**
@@ -1,2 +1,4 @@
1
1
  export { default as claudeCodeAgentPlugin } from "@tokentop/agent-claude-code";
2
+ export { default as copilotCliAgentPlugin } from "@tokentop/agent-copilot-cli";
3
+ export { default as cursorAgentPlugin } from "@tokentop/agent-cursor";
2
4
  export { default as opencodeAgentPlugin } from "@tokentop/agent-opencode";
@@ -1,9 +1,8 @@
1
+ import type { AuthSources, OpenCodeAuthEntry, PluginPermissions } from "@tokentop/plugin-sdk";
2
+ import { PluginPermissionError } from "@tokentop/plugin-sdk";
1
3
  import * as fs from "fs/promises";
2
4
  import * as os from "os";
3
5
  import * as path from "path";
4
- import type { PluginPermissions } from "./types/base.ts";
5
- import { PluginPermissionError } from "./types/base.ts";
6
- import type { AuthSources, OpenCodeAuthEntry } from "./types/provider.ts";
7
6
 
8
7
  const OPENCODE_AUTH_PATH = path.join(os.homedir(), ".local/share/opencode/auth.json");
9
8
  const OPENCODE_CONFIG_PATH = path.join(os.homedir(), ".config/opencode/opencode.json");
@@ -5,11 +5,11 @@
5
5
  * with safeInvoke for error isolation and circuit breaker protection.
6
6
  */
7
7
 
8
+ import type { BasePlugin, PluginLifecycleContext, PluginLogger } from "@tokentop/plugin-sdk";
8
9
  import { safeInvoke } from "./plugin-host.ts";
9
10
  import { pluginRegistry } from "./registry.ts";
10
11
  import { createPluginLogger } from "./sandbox.ts";
11
12
  import { runInPluginGuard } from "./sandbox-guard.ts";
12
- import type { BasePlugin, PluginLifecycleContext, PluginLogger } from "./types/base.ts";
13
13
 
14
14
  // ---------------------------------------------------------------------------
15
15
  // State machine
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+ import { CURRENT_API_VERSION } from "@tokentop/plugin-sdk";
2
3
  import { validatePlugin } from "./loader.ts";
3
- import { CURRENT_API_VERSION } from "./types/base.ts";
4
4
 
5
5
  const validPlugin = {
6
6
  id: "test-plugin",
@@ -1,14 +1,22 @@
1
+ import type { AnyPlugin, BasePlugin, PluginType } from "@tokentop/plugin-sdk";
2
+ import { CURRENT_API_VERSION } from "@tokentop/plugin-sdk";
1
3
  import * as fs from "fs/promises";
2
4
  import * as os from "os";
3
5
  import * as path from "path";
4
6
  import { PATHS } from "@/storage/paths.ts";
5
- import { CURRENT_API_VERSION } from "./types/base.ts";
6
- import type {
7
- AnyPlugin,
8
- PluginLoadResult,
9
- PluginType,
10
- PluginValidationResult,
11
- } from "./types/index.ts";
7
+
8
+ interface PluginValidationResult {
9
+ valid: boolean;
10
+ errors: string[];
11
+ warnings: string[];
12
+ }
13
+
14
+ interface PluginLoadResult<T extends BasePlugin = BasePlugin> {
15
+ success: boolean;
16
+ plugin?: T;
17
+ error?: string;
18
+ source: "builtin" | "local" | "npm";
19
+ }
12
20
 
13
21
  const CUSTOM_PLUGINS_DIR = PATHS.config.plugins;
14
22
 
@@ -1,8 +1,11 @@
1
+ import type {
2
+ NotificationEvent,
3
+ NotificationPlugin,
4
+ ProviderUsageData,
5
+ } from "@tokentop/plugin-sdk";
1
6
  import type { AppConfig } from "@/config/schema.ts";
2
7
  import { safeInvoke } from "./plugin-host.ts";
3
8
  import { createPluginLogger } from "./sandbox.ts";
4
- import type { NotificationEvent, NotificationPlugin } from "./types/notification.ts";
5
- import type { ProviderUsageData } from "./types/provider.ts";
6
9
 
7
10
  interface DedupEntry {
8
11
  key: string;
@@ -2,7 +2,7 @@ import type {
2
2
  NotificationContext,
3
3
  NotificationEvent,
4
4
  NotificationPlugin,
5
- } from "../types/notification.ts";
5
+ } from "@tokentop/plugin-sdk";
6
6
 
7
7
  export const terminalBellPlugin: NotificationPlugin = {
8
8
  apiVersion: 2,
@@ -2,7 +2,7 @@ import type {
2
2
  NotificationContext,
3
3
  NotificationEvent,
4
4
  NotificationPlugin,
5
- } from "../types/notification.ts";
5
+ } from "@tokentop/plugin-sdk";
6
6
 
7
7
  export const visualFlashPlugin: NotificationPlugin = {
8
8
  apiVersion: 2,
@@ -1,27 +1,17 @@
1
+ import type { PluginContext, PluginPermissions, PluginStorage } from "@tokentop/plugin-sdk";
2
+ import { isDatabaseInitialized } from "@/storage/db.ts";
1
3
  import {
2
- getDatabase,
3
4
  pluginStorageDelete,
4
5
  pluginStorageGet,
5
6
  pluginStorageHas,
6
7
  pluginStorageSet,
7
- } from "@/storage/database.ts";
8
+ } from "@/storage/repos/pluginStorage.ts";
8
9
  import { createAuthSources } from "./auth-sources.ts";
9
10
  import { createPluginLogger, createSandboxedHttpClient } from "./sandbox.ts";
10
11
  import { deepFreeze } from "./sandbox-guard.ts";
11
- import type { PluginPermissions } from "./types/base.ts";
12
- import type { PluginContext, PluginStorage } from "./types/provider.ts";
13
-
14
- let dbAvailable: boolean | null = null;
15
12
 
16
13
  function isDbAvailable(): boolean {
17
- if (dbAvailable !== null) return dbAvailable;
18
- try {
19
- getDatabase();
20
- dbAvailable = true;
21
- } catch {
22
- dbAvailable = false;
23
- }
24
- return dbAvailable;
14
+ return isDatabaseInitialized();
25
15
  }
26
16
 
27
17
  function createPluginStorage(pluginId: string): PluginStorage {
@@ -44,11 +34,6 @@ function createPluginStorage(pluginId: string): PluginStorage {
44
34
  },
45
35
  };
46
36
  }
47
-
48
- export function resetDbAvailableCache(): void {
49
- dbAvailable = null;
50
- }
51
-
52
37
  export function createPluginContext(
53
38
  pluginId: string,
54
39
  permissions: PluginPermissions,
@@ -1,4 +1,3 @@
1
- import { execFileSync } from "child_process";
2
1
  import type {
3
2
  CredentialResult,
4
3
  Credentials,
@@ -8,7 +7,8 @@ import type {
8
7
  ProviderFetchContext,
9
8
  ProviderPlugin,
10
9
  ProviderUsageData,
11
- } from "../types/provider.ts";
10
+ } from "@tokentop/plugin-sdk";
11
+ import { execFileSync } from "child_process";
12
12
 
13
13
  const TOKEN_EXPIRY_BUFFER_MS = 5 * 60 * 1000;
14
14
 
@@ -9,7 +9,7 @@ import type {
9
9
  ProviderUsageData,
10
10
  RefreshedCredentials,
11
11
  UsageLimit,
12
- } from "../types/provider.ts";
12
+ } from "@tokentop/plugin-sdk";
13
13
 
14
14
  const ANTIGRAVITY_ENDPOINTS = [
15
15
  "https://daily-cloudcode-pa.sandbox.googleapis.com",
@@ -0,0 +1,189 @@
1
+ import type {
2
+ CredentialResult,
3
+ Credentials,
4
+ PluginContext,
5
+ ProviderAuth,
6
+ ProviderFetchContext,
7
+ ProviderPlugin,
8
+ ProviderUsageData,
9
+ } from "@tokentop/plugin-sdk";
10
+
11
+ const CHUTES_QUOTA_URL = "https://api.chutes.ai/users/me/quota_usage/me";
12
+
13
+ interface ChutesQuotaResponse {
14
+ quota?: number;
15
+ used?: number;
16
+ }
17
+
18
+ export const chutesPlugin: ProviderPlugin = {
19
+ apiVersion: 2,
20
+ id: "chutes",
21
+ type: "provider",
22
+ name: "Chutes",
23
+ version: "1.0.0",
24
+
25
+ meta: {
26
+ description: "Chutes AI API quota and usage tracking",
27
+ homepage: "https://chutes.ai",
28
+ brandColor: "#6366f1",
29
+ },
30
+
31
+ permissions: {
32
+ network: {
33
+ enabled: true,
34
+ allowedDomains: ["api.chutes.ai"],
35
+ },
36
+ filesystem: {
37
+ read: true,
38
+ paths: ["~/.local/share/opencode"],
39
+ },
40
+ env: {
41
+ read: true,
42
+ vars: ["CHUTES_API_KEY"],
43
+ },
44
+ },
45
+
46
+ capabilities: {
47
+ usageLimits: true,
48
+ apiRateLimits: false,
49
+ tokenUsage: false,
50
+ actualCosts: false,
51
+ },
52
+
53
+ auth: {
54
+ async discover(ctx: PluginContext): Promise<CredentialResult> {
55
+ const entry = await ctx.authSources.opencode.getProviderEntry("chutes");
56
+ if (entry) {
57
+ if (entry.type === "api" && entry.key) {
58
+ return { ok: true, credentials: { apiKey: entry.key, source: "opencode" } };
59
+ }
60
+ if (entry.type === "wellknown" && (entry.token || entry.key)) {
61
+ return {
62
+ ok: true,
63
+ credentials: { apiKey: (entry.token || entry.key)!, source: "opencode" },
64
+ };
65
+ }
66
+ if (entry.type === "oauth" && entry.access) {
67
+ return { ok: true, credentials: { apiKey: entry.access, source: "opencode" } };
68
+ }
69
+ }
70
+
71
+ const apiKey = ctx.authSources.env.get("CHUTES_API_KEY");
72
+ if (apiKey) {
73
+ return { ok: true, credentials: { apiKey, source: "env" } };
74
+ }
75
+
76
+ return {
77
+ ok: false,
78
+ reason: "missing",
79
+ message: "No Chutes API key found. Configure Chutes in OpenCode.",
80
+ };
81
+ },
82
+
83
+ isConfigured(credentials: Credentials): boolean {
84
+ return !!(credentials.apiKey || credentials.oauth?.accessToken);
85
+ },
86
+ } satisfies ProviderAuth,
87
+
88
+ async fetchUsage(ctx: ProviderFetchContext): Promise<ProviderUsageData> {
89
+ const { credentials, http, logger: log } = ctx;
90
+
91
+ const token = credentials.apiKey || credentials.oauth?.accessToken;
92
+
93
+ if (!token) {
94
+ return {
95
+ fetchedAt: Date.now(),
96
+ error: "API key required. Configure Chutes in OpenCode.",
97
+ };
98
+ }
99
+
100
+ try {
101
+ const response = await http.fetch(CHUTES_QUOTA_URL, {
102
+ method: "GET",
103
+ headers: {
104
+ Authorization: `Bearer ${token}`,
105
+ Accept: "application/json",
106
+ },
107
+ });
108
+
109
+ if (!response.ok) {
110
+ log.warn("Failed to fetch Chutes usage", { status: response.status });
111
+
112
+ if (response.status === 401 || response.status === 403) {
113
+ return {
114
+ fetchedAt: Date.now(),
115
+ error: "Authorization failed. Check your Chutes API key.",
116
+ };
117
+ }
118
+
119
+ return {
120
+ fetchedAt: Date.now(),
121
+ error: `API error: ${response.status} ${response.statusText}`,
122
+ };
123
+ }
124
+
125
+ const data = (await response.json()) as ChutesQuotaResponse;
126
+
127
+ if (!data || typeof data.quota !== "number" || typeof data.used !== "number") {
128
+ return {
129
+ fetchedAt: Date.now(),
130
+ planType: "Chutes",
131
+ allowed: true,
132
+ };
133
+ }
134
+
135
+ const quota = data.quota;
136
+ const used = data.used;
137
+ const usedPercent = quota > 0 ? Math.round((used / quota) * 100) : 0;
138
+
139
+ const planType = getTierFromQuota(quota);
140
+ const resetAt = calculateNextReset();
141
+ const limitReached = usedPercent >= 100;
142
+
143
+ const result: ProviderUsageData = {
144
+ planType,
145
+ allowed: !limitReached,
146
+ limitReached,
147
+ fetchedAt: Date.now(),
148
+ };
149
+
150
+ if (usedPercent !== null) {
151
+ result.limits = {
152
+ primary: {
153
+ usedPercent,
154
+ label: "Daily quota",
155
+ resetsAt: resetAt,
156
+ windowMinutes: 1440,
157
+ },
158
+ };
159
+ }
160
+
161
+ return result;
162
+ } catch (err) {
163
+ log.error("Failed to fetch Chutes usage", { error: err });
164
+ return {
165
+ fetchedAt: Date.now(),
166
+ error: err instanceof Error ? err.message : "Unknown error",
167
+ };
168
+ }
169
+ },
170
+ };
171
+
172
+ function getTierFromQuota(quota: number): string {
173
+ const tierMap: Record<number, string> = {
174
+ 200: "Legacy",
175
+ 300: "Base",
176
+ 2000: "Plus",
177
+ 5000: "Pro",
178
+ };
179
+
180
+ return tierMap[quota] ?? `Custom (${quota})`;
181
+ }
182
+
183
+ function calculateNextReset(): number {
184
+ const now = new Date();
185
+ const tomorrow = new Date(now);
186
+ tomorrow.setUTCDate(tomorrow.getUTCDate() + 1);
187
+ tomorrow.setUTCHours(0, 0, 0, 0);
188
+ return tomorrow.getTime();
189
+ }
@@ -7,7 +7,7 @@ import type {
7
7
  ProviderFetchContext,
8
8
  ProviderPlugin,
9
9
  ProviderUsageData,
10
- } from "../types/provider.ts";
10
+ } from "@tokentop/plugin-sdk";
11
11
 
12
12
  interface CodexCliCredentials {
13
13
  access_token?: string;
@@ -9,7 +9,7 @@ import type {
9
9
  ProviderUsageData,
10
10
  RefreshedCredentials,
11
11
  UsageLimit,
12
- } from "../types/provider.ts";
12
+ } from "@tokentop/plugin-sdk";
13
13
 
14
14
  const GOOGLE_ENDPOINT = "https://cloudcode-pa.googleapis.com";
15
15
 
@@ -7,7 +7,7 @@ import type {
7
7
  ProviderPlugin,
8
8
  ProviderUsageData,
9
9
  UsageLimit,
10
- } from "../types/provider.ts";
10
+ } from "@tokentop/plugin-sdk";
11
11
 
12
12
  interface CopilotUserResponse {
13
13
  access_type_sku?: string;
@@ -1,5 +1,6 @@
1
1
  export { anthropicPlugin } from "./anthropic.ts";
2
2
  export { antigravityPlugin } from "./antigravity.ts";
3
+ export { chutesPlugin } from "./chutes.ts";
3
4
  export { codexPlugin } from "./codex.ts";
4
5
  export { geminiPlugin } from "./gemini.ts";
5
6
  export { githubCopilotPlugin } from "./github-copilot.ts";
@@ -6,7 +6,7 @@ import type {
6
6
  ProviderFetchContext,
7
7
  ProviderPlugin,
8
8
  ProviderUsageData,
9
- } from "../types/provider.ts";
9
+ } from "@tokentop/plugin-sdk";
10
10
 
11
11
  const MINIMAX_USAGE_URL = "https://platform.minimax.io/v1/api/openplatform/coding_plan/remains";
12
12
 
@@ -6,7 +6,7 @@ import type {
6
6
  ProviderFetchContext,
7
7
  ProviderPlugin,
8
8
  ProviderUsageData,
9
- } from "../types/provider.ts";
9
+ } from "@tokentop/plugin-sdk";
10
10
 
11
11
  interface UsageBucket {
12
12
  object: string;
@@ -6,7 +6,7 @@ import type {
6
6
  ProviderFetchContext,
7
7
  ProviderPlugin,
8
8
  ProviderUsageData,
9
- } from "../types/provider.ts";
9
+ } from "@tokentop/plugin-sdk";
10
10
 
11
11
  export const opencodeZenPlugin: ProviderPlugin = {
12
12
  apiVersion: 2,
@@ -6,7 +6,7 @@ import type {
6
6
  ProviderFetchContext,
7
7
  ProviderPlugin,
8
8
  ProviderUsageData,
9
- } from "../types/provider.ts";
9
+ } from "@tokentop/plugin-sdk";
10
10
 
11
11
  /**
12
12
  * Perplexity Shadow API Discovery (January 2026):
@@ -7,7 +7,7 @@ import type {
7
7
  ProviderPlugin,
8
8
  ProviderUsageData,
9
9
  UsageLimit,
10
- } from "../types/provider.ts";
10
+ } from "@tokentop/plugin-sdk";
11
11
 
12
12
  const ZAI_USAGE_URL = "https://api.z.ai/api/monitor/usage/quota/limit";
13
13
 
@@ -1,11 +1,3 @@
1
- import type { PluginsConfig } from "@/config/schema.ts";
2
- import {
3
- discoverLocalPlugins,
4
- loadLocalPlugin,
5
- loadNpmPlugin,
6
- resolvePluginPath,
7
- } from "./loader.ts";
8
- import { installAllNpmPlugins, resolveNpmPluginPath } from "./npm-installer.ts";
9
1
  import type {
10
2
  AgentPlugin,
11
3
  AnyPlugin,
@@ -14,7 +6,15 @@ import type {
14
6
  PluginType,
15
7
  ProviderPlugin,
16
8
  ThemePlugin,
17
- } from "./types/index.ts";
9
+ } from "@tokentop/plugin-sdk";
10
+ import type { PluginsConfig } from "@/config/schema.ts";
11
+ import {
12
+ discoverLocalPlugins,
13
+ loadLocalPlugin,
14
+ loadNpmPlugin,
15
+ resolvePluginPath,
16
+ } from "./loader.ts";
17
+ import { installAllNpmPlugins, resolveNpmPluginPath } from "./npm-installer.ts";
18
18
 
19
19
  export type PluginSource = "builtin" | "local" | "npm";
20
20
 
@@ -1,11 +1,11 @@
1
1
  import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
+ import { PluginPermissionError } from "@tokentop/plugin-sdk";
2
3
  import {
3
4
  deepFreeze,
4
5
  getActivePluginGuard,
5
6
  installGlobalFetchGuard,
6
7
  runInPluginGuard,
7
8
  } from "./sandbox-guard.ts";
8
- import { PluginPermissionError } from "./types/base.ts";
9
9
 
10
10
  const originalFetch = globalThis.fetch;
11
11
  const fetchCalls: string[] = [];
@@ -11,9 +11,9 @@
11
11
  * 2. **Deep-freeze** — prevents plugins from mutating the PluginContext.
12
12
  */
13
13
 
14
+ import { PluginPermissionError, type PluginPermissions } from "@tokentop/plugin-sdk";
14
15
  import { AsyncLocalStorage } from "async_hooks";
15
16
  import { createPluginLogger } from "./sandbox.ts";
16
- import { PluginPermissionError, type PluginPermissions } from "./types/base.ts";
17
17
 
18
18
  // ---------------------------------------------------------------------------
19
19
  // Plugin execution context (AsyncLocalStorage)
@@ -3,7 +3,7 @@ import {
3
3
  type PluginLogger,
4
4
  PluginPermissionError,
5
5
  type PluginPermissions,
6
- } from "./types/index.ts";
6
+ } from "@tokentop/plugin-sdk";
7
7
 
8
8
  export function createSandboxedHttpClient(
9
9
  pluginId: string,
@@ -1,4 +1,4 @@
1
- import type { ThemePlugin } from "../types/theme.ts";
1
+ import type { ThemePlugin } from "@tokentop/plugin-sdk";
2
2
 
3
3
  export const catppuccinLatteTheme: ThemePlugin = {
4
4
  apiVersion: 2,
@@ -1,4 +1,4 @@
1
- import type { ThemePlugin } from "../types/theme.ts";
1
+ import type { ThemePlugin } from "@tokentop/plugin-sdk";
2
2
 
3
3
  export const catppuccinMochaTheme: ThemePlugin = {
4
4
  apiVersion: 2,
@@ -1,4 +1,4 @@
1
- import type { ThemePlugin } from "../types/theme.ts";
1
+ import type { ThemePlugin } from "@tokentop/plugin-sdk";
2
2
 
3
3
  export const claudeCodeTheme: ThemePlugin = {
4
4
  apiVersion: 2,
@@ -1,4 +1,4 @@
1
- import type { ThemePlugin } from "../types/theme.ts";
1
+ import type { ThemePlugin } from "@tokentop/plugin-sdk";
2
2
 
3
3
  export const draculaTheme: ThemePlugin = {
4
4
  apiVersion: 2,
@@ -1,4 +1,4 @@
1
- import type { ThemePlugin } from "../types/theme.ts";
1
+ import type { ThemePlugin } from "@tokentop/plugin-sdk";
2
2
 
3
3
  export const githubLightTheme: ThemePlugin = {
4
4
  apiVersion: 2,
@@ -1,4 +1,4 @@
1
- import type { ThemePlugin } from "../types/theme.ts";
1
+ import type { ThemePlugin } from "@tokentop/plugin-sdk";
2
2
 
3
3
  export const gruvboxDarkTheme: ThemePlugin = {
4
4
  apiVersion: 2,
@@ -1,4 +1,4 @@
1
- import type { ThemePlugin } from "../types/theme.ts";
1
+ import type { ThemePlugin } from "@tokentop/plugin-sdk";
2
2
 
3
3
  export const gruvboxLightTheme: ThemePlugin = {
4
4
  apiVersion: 2,