claudedesk 1.0.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/LICENSE +21 -0
- package/README.md +431 -0
- package/config/repos.example.json +128 -0
- package/config/settings.example.json +64 -0
- package/config/skills/code-review.md +76 -0
- package/config/skills/full-check.md +26 -0
- package/config/skills/lint-fix.md +23 -0
- package/dist/api/agent-routes.d.ts +2 -0
- package/dist/api/agent-routes.d.ts.map +1 -0
- package/dist/api/agent-routes.js +251 -0
- package/dist/api/agent-routes.js.map +1 -0
- package/dist/api/app-routes.d.ts +2 -0
- package/dist/api/app-routes.d.ts.map +1 -0
- package/dist/api/app-routes.js +150 -0
- package/dist/api/app-routes.js.map +1 -0
- package/dist/api/docker-routes.d.ts +2 -0
- package/dist/api/docker-routes.d.ts.map +1 -0
- package/dist/api/docker-routes.js +167 -0
- package/dist/api/docker-routes.js.map +1 -0
- package/dist/api/middleware.d.ts +6 -0
- package/dist/api/middleware.d.ts.map +1 -0
- package/dist/api/middleware.js +293 -0
- package/dist/api/middleware.js.map +1 -0
- package/dist/api/pin-auth.d.ts +65 -0
- package/dist/api/pin-auth.d.ts.map +1 -0
- package/dist/api/pin-auth.js +218 -0
- package/dist/api/pin-auth.js.map +1 -0
- package/dist/api/routes.d.ts +2 -0
- package/dist/api/routes.d.ts.map +1 -0
- package/dist/api/routes.js +473 -0
- package/dist/api/routes.js.map +1 -0
- package/dist/api/settings-routes.d.ts +2 -0
- package/dist/api/settings-routes.d.ts.map +1 -0
- package/dist/api/settings-routes.js +570 -0
- package/dist/api/settings-routes.js.map +1 -0
- package/dist/api/skill-routes.d.ts +2 -0
- package/dist/api/skill-routes.d.ts.map +1 -0
- package/dist/api/skill-routes.js +88 -0
- package/dist/api/skill-routes.js.map +1 -0
- package/dist/api/terminal-routes.d.ts +2 -0
- package/dist/api/terminal-routes.d.ts.map +1 -0
- package/dist/api/terminal-routes.js +3524 -0
- package/dist/api/terminal-routes.js.map +1 -0
- package/dist/api/tunnel-routes.d.ts +2 -0
- package/dist/api/tunnel-routes.d.ts.map +1 -0
- package/dist/api/tunnel-routes.js +196 -0
- package/dist/api/tunnel-routes.js.map +1 -0
- package/dist/api/workspace-routes.d.ts +3 -0
- package/dist/api/workspace-routes.d.ts.map +1 -0
- package/dist/api/workspace-routes.js +649 -0
- package/dist/api/workspace-routes.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +276 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/assets/index-B4r0njGe.js +780 -0
- package/dist/client/assets/index-CY_9MyE0.css +1 -0
- package/dist/client/favicon.svg +5 -0
- package/dist/client/icons/icon-192.svg +5 -0
- package/dist/client/icons/icon-512.svg +5 -0
- package/dist/client/icons/logo-with-message.png +0 -0
- package/dist/client/icons/logo.png +0 -0
- package/dist/client/index.html +25 -0
- package/dist/client/manifest.json +62 -0
- package/dist/client/sw.js +243 -0
- package/dist/config/agent-usage.d.ts +34 -0
- package/dist/config/agent-usage.d.ts.map +1 -0
- package/dist/config/agent-usage.js +87 -0
- package/dist/config/agent-usage.js.map +1 -0
- package/dist/config/repos.d.ts +34 -0
- package/dist/config/repos.d.ts.map +1 -0
- package/dist/config/repos.js +412 -0
- package/dist/config/repos.js.map +1 -0
- package/dist/config/settings.d.ts +634 -0
- package/dist/config/settings.d.ts.map +1 -0
- package/dist/config/settings.js +459 -0
- package/dist/config/settings.js.map +1 -0
- package/dist/config/skills.d.ts +18 -0
- package/dist/config/skills.d.ts.map +1 -0
- package/dist/config/skills.js +174 -0
- package/dist/config/skills.js.map +1 -0
- package/dist/config/workspaces.d.ts +961 -0
- package/dist/config/workspaces.d.ts.map +1 -0
- package/dist/config/workspaces.js +482 -0
- package/dist/config/workspaces.js.map +1 -0
- package/dist/core/app-manager.d.ts +85 -0
- package/dist/core/app-manager.d.ts.map +1 -0
- package/dist/core/app-manager.js +447 -0
- package/dist/core/app-manager.js.map +1 -0
- package/dist/core/claude-invoker.d.ts +49 -0
- package/dist/core/claude-invoker.d.ts.map +1 -0
- package/dist/core/claude-invoker.js +583 -0
- package/dist/core/claude-invoker.js.map +1 -0
- package/dist/core/claude-session-reader.d.ts +25 -0
- package/dist/core/claude-session-reader.d.ts.map +1 -0
- package/dist/core/claude-session-reader.js +184 -0
- package/dist/core/claude-session-reader.js.map +1 -0
- package/dist/core/claude-usage-query.d.ts +78 -0
- package/dist/core/claude-usage-query.d.ts.map +1 -0
- package/dist/core/claude-usage-query.js +294 -0
- package/dist/core/claude-usage-query.js.map +1 -0
- package/dist/core/git-credential-helper.d.ts +57 -0
- package/dist/core/git-credential-helper.d.ts.map +1 -0
- package/dist/core/git-credential-helper.js +176 -0
- package/dist/core/git-credential-helper.js.map +1 -0
- package/dist/core/git-sandbox.d.ts +135 -0
- package/dist/core/git-sandbox.d.ts.map +1 -0
- package/dist/core/git-sandbox.js +907 -0
- package/dist/core/git-sandbox.js.map +1 -0
- package/dist/core/github-integration.d.ts +66 -0
- package/dist/core/github-integration.d.ts.map +1 -0
- package/dist/core/github-integration.js +350 -0
- package/dist/core/github-integration.js.map +1 -0
- package/dist/core/github-oauth.d.ts +88 -0
- package/dist/core/github-oauth.d.ts.map +1 -0
- package/dist/core/github-oauth.js +244 -0
- package/dist/core/github-oauth.js.map +1 -0
- package/dist/core/gitlab-integration.d.ts +66 -0
- package/dist/core/gitlab-integration.d.ts.map +1 -0
- package/dist/core/gitlab-integration.js +353 -0
- package/dist/core/gitlab-integration.js.map +1 -0
- package/dist/core/gitlab-oauth.d.ts +100 -0
- package/dist/core/gitlab-oauth.d.ts.map +1 -0
- package/dist/core/gitlab-oauth.js +366 -0
- package/dist/core/gitlab-oauth.js.map +1 -0
- package/dist/core/insights-extractor.d.ts +68 -0
- package/dist/core/insights-extractor.d.ts.map +1 -0
- package/dist/core/insights-extractor.js +402 -0
- package/dist/core/insights-extractor.js.map +1 -0
- package/dist/core/logger.d.ts +27 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +70 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/process-runner.d.ts +27 -0
- package/dist/core/process-runner.d.ts.map +1 -0
- package/dist/core/process-runner.js +147 -0
- package/dist/core/process-runner.js.map +1 -0
- package/dist/core/project-detector.d.ts +30 -0
- package/dist/core/project-detector.d.ts.map +1 -0
- package/dist/core/project-detector.js +482 -0
- package/dist/core/project-detector.js.map +1 -0
- package/dist/core/qr-generator.d.ts +18 -0
- package/dist/core/qr-generator.d.ts.map +1 -0
- package/dist/core/qr-generator.js +61 -0
- package/dist/core/qr-generator.js.map +1 -0
- package/dist/core/remote-tunnel-manager.d.ts +59 -0
- package/dist/core/remote-tunnel-manager.d.ts.map +1 -0
- package/dist/core/remote-tunnel-manager.js +235 -0
- package/dist/core/remote-tunnel-manager.js.map +1 -0
- package/dist/core/shared-docker-manager.d.ts +41 -0
- package/dist/core/shared-docker-manager.d.ts.map +1 -0
- package/dist/core/shared-docker-manager.js +409 -0
- package/dist/core/shared-docker-manager.js.map +1 -0
- package/dist/core/skill-executor.d.ts +25 -0
- package/dist/core/skill-executor.d.ts.map +1 -0
- package/dist/core/skill-executor.js +171 -0
- package/dist/core/skill-executor.js.map +1 -0
- package/dist/core/terminal-session.d.ts +149 -0
- package/dist/core/terminal-session.d.ts.map +1 -0
- package/dist/core/terminal-session.js +2340 -0
- package/dist/core/terminal-session.js.map +1 -0
- package/dist/core/tunnel-manager.d.ts +35 -0
- package/dist/core/tunnel-manager.d.ts.map +1 -0
- package/dist/core/tunnel-manager.js +137 -0
- package/dist/core/tunnel-manager.js.map +1 -0
- package/dist/core/usage-manager.d.ts +57 -0
- package/dist/core/usage-manager.d.ts.map +1 -0
- package/dist/core/usage-manager.js +363 -0
- package/dist/core/usage-manager.js.map +1 -0
- package/dist/core/ws-manager.d.ts +39 -0
- package/dist/core/ws-manager.d.ts.map +1 -0
- package/dist/core/ws-manager.js +190 -0
- package/dist/core/ws-manager.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +229 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +868 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +119 -0
- package/dist/types.js.map +1 -0
- package/package.json +96 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
/**
|
|
5
|
+
* Convert a repo path to Claude's project folder name format
|
|
6
|
+
* e.g., C:\Users\carlo\Desktop\repos\my-app -> C--Users-carlo-Desktop-repos-my-app
|
|
7
|
+
*/
|
|
8
|
+
function pathToClaudeProjectName(repoPath) {
|
|
9
|
+
// Claude converts:
|
|
10
|
+
// - Colon (:) to dash (-)
|
|
11
|
+
// - Backslash (\) to dash (-)
|
|
12
|
+
// - Forward slash (/) to dash (-)
|
|
13
|
+
// So C:\Users\carlo becomes C--Users-carlo (colon and backslash both become dashes)
|
|
14
|
+
return repoPath
|
|
15
|
+
.replace(/:/g, '-')
|
|
16
|
+
.replace(/\\/g, '-')
|
|
17
|
+
.replace(/\//g, '-');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get the Claude projects directory
|
|
21
|
+
*/
|
|
22
|
+
function getClaudeProjectsDir() {
|
|
23
|
+
return join(homedir(), '.claude', 'projects');
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Read all Claude sessions for a given repository path
|
|
27
|
+
*/
|
|
28
|
+
export function getClaudeSessions(repoPath) {
|
|
29
|
+
const projectsDir = getClaudeProjectsDir();
|
|
30
|
+
const projectName = pathToClaudeProjectName(repoPath);
|
|
31
|
+
const projectDir = join(projectsDir, projectName);
|
|
32
|
+
console.log(`[ClaudeSessionReader] Looking for sessions:`);
|
|
33
|
+
console.log(`[ClaudeSessionReader] Repo path: ${repoPath}`);
|
|
34
|
+
console.log(`[ClaudeSessionReader] Project name: ${projectName}`);
|
|
35
|
+
console.log(`[ClaudeSessionReader] Project dir: ${projectDir}`);
|
|
36
|
+
if (!existsSync(projectDir)) {
|
|
37
|
+
console.log(`[ClaudeSessionReader] No Claude project folder found at ${projectDir}`);
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const sessions = [];
|
|
41
|
+
try {
|
|
42
|
+
const files = readdirSync(projectDir);
|
|
43
|
+
for (const file of files) {
|
|
44
|
+
if (!file.endsWith('.jsonl'))
|
|
45
|
+
continue;
|
|
46
|
+
const filePath = join(projectDir, file);
|
|
47
|
+
const sessionId = file.replace('.jsonl', '');
|
|
48
|
+
try {
|
|
49
|
+
const stat = statSync(filePath);
|
|
50
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
51
|
+
const lines = content.split('\n').filter(line => line.trim());
|
|
52
|
+
if (lines.length === 0)
|
|
53
|
+
continue;
|
|
54
|
+
// Parse session data
|
|
55
|
+
let summary = '';
|
|
56
|
+
let branch;
|
|
57
|
+
let messageCount = 0;
|
|
58
|
+
let firstUserMessage = '';
|
|
59
|
+
let lastTimestamp;
|
|
60
|
+
for (const line of lines) {
|
|
61
|
+
try {
|
|
62
|
+
const data = JSON.parse(line);
|
|
63
|
+
// Get the first user message as the title (like Claude Code does)
|
|
64
|
+
if (data.type === 'user' && data.message?.role === 'user' && data.message?.content) {
|
|
65
|
+
messageCount++;
|
|
66
|
+
if (!firstUserMessage) {
|
|
67
|
+
// Extract first user message content
|
|
68
|
+
const content = typeof data.message.content === 'string'
|
|
69
|
+
? data.message.content
|
|
70
|
+
: Array.isArray(data.message.content)
|
|
71
|
+
? data.message.content.find((c) => c.type === 'text')?.content || ''
|
|
72
|
+
: '';
|
|
73
|
+
firstUserMessage = content.split('\n')[0].trim(); // First line only
|
|
74
|
+
}
|
|
75
|
+
// Track timestamp
|
|
76
|
+
if (data.timestamp) {
|
|
77
|
+
lastTimestamp = new Date(data.timestamp);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Count assistant messages too
|
|
81
|
+
if (data.type === 'assistant' && data.message?.role === 'assistant') {
|
|
82
|
+
messageCount++;
|
|
83
|
+
if (data.timestamp) {
|
|
84
|
+
lastTimestamp = new Date(data.timestamp);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Get git branch
|
|
88
|
+
if (data.gitBranch && !branch) {
|
|
89
|
+
branch = data.gitBranch;
|
|
90
|
+
}
|
|
91
|
+
// Also check for summaries as fallback
|
|
92
|
+
if (data.type === 'summary' && data.summary && !summary) {
|
|
93
|
+
summary = data.summary;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Skip unparseable lines
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Use first user message as title, fall back to summary
|
|
101
|
+
const displayTitle = firstUserMessage || summary || 'Untitled session';
|
|
102
|
+
sessions.push({
|
|
103
|
+
id: sessionId,
|
|
104
|
+
summary: displayTitle,
|
|
105
|
+
timestamp: lastTimestamp || stat.mtime,
|
|
106
|
+
messageCount,
|
|
107
|
+
branch,
|
|
108
|
+
filePath,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
console.error(`[ClaudeSessionReader] Error reading session ${file}:`, error);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Sort by timestamp (most recent first)
|
|
116
|
+
sessions.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
|
117
|
+
console.log(`[ClaudeSessionReader] Found ${sessions.length} sessions for ${repoPath}`);
|
|
118
|
+
return sessions;
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
console.error('[ClaudeSessionReader] Error reading sessions:', error);
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Format relative time (e.g., "10 minutes ago", "3 days ago")
|
|
127
|
+
*/
|
|
128
|
+
export function formatRelativeTime(date) {
|
|
129
|
+
const now = Date.now();
|
|
130
|
+
const diff = now - date.getTime();
|
|
131
|
+
const seconds = Math.floor(diff / 1000);
|
|
132
|
+
const minutes = Math.floor(seconds / 60);
|
|
133
|
+
const hours = Math.floor(minutes / 60);
|
|
134
|
+
const days = Math.floor(hours / 24);
|
|
135
|
+
const weeks = Math.floor(days / 7);
|
|
136
|
+
if (weeks > 0)
|
|
137
|
+
return `${weeks} week${weeks > 1 ? 's' : ''} ago`;
|
|
138
|
+
if (days > 0)
|
|
139
|
+
return `${days} day${days > 1 ? 's' : ''} ago`;
|
|
140
|
+
if (hours > 0)
|
|
141
|
+
return `${hours} hour${hours > 1 ? 's' : ''} ago`;
|
|
142
|
+
if (minutes > 0)
|
|
143
|
+
return `${minutes} minute${minutes > 1 ? 's' : ''} ago`;
|
|
144
|
+
return 'just now';
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Format session list for display (similar to Claude Code's /resume output)
|
|
148
|
+
*/
|
|
149
|
+
export function formatSessionList(sessions, limit = 20) {
|
|
150
|
+
if (sessions.length === 0) {
|
|
151
|
+
return '*No Claude sessions found for this repository.*\n\nStart a conversation to create your first session.';
|
|
152
|
+
}
|
|
153
|
+
const displaySessions = sessions.slice(0, limit);
|
|
154
|
+
const lines = displaySessions.map((session, index) => {
|
|
155
|
+
const relTime = formatRelativeTime(session.timestamp);
|
|
156
|
+
const msgCount = session.messageCount;
|
|
157
|
+
const branch = session.branch ? ` · ${session.branch}` : '';
|
|
158
|
+
// Truncate summary if too long
|
|
159
|
+
const maxSummaryLen = 80;
|
|
160
|
+
const summary = session.summary.length > maxSummaryLen
|
|
161
|
+
? session.summary.slice(0, maxSummaryLen) + '...'
|
|
162
|
+
: session.summary;
|
|
163
|
+
return `**${index + 1}.** ${summary}\n _${relTime} · ${msgCount} messages${branch}_`;
|
|
164
|
+
});
|
|
165
|
+
const header = `**Resume Session** _(${sessions.length} sessions)_\n`;
|
|
166
|
+
const footer = sessions.length > limit
|
|
167
|
+
? `\n\n_Showing ${limit} of ${sessions.length} sessions_`
|
|
168
|
+
: '';
|
|
169
|
+
const instructions = '\n\n_Type \`/resume <number>\` to resume a session, or use tabs to switch ClaudeDesk sessions._';
|
|
170
|
+
return header + '\n' + lines.join('\n\n') + footer + instructions;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Get a specific session by index (1-based) or ID
|
|
174
|
+
*/
|
|
175
|
+
export function getSessionByRef(sessions, ref) {
|
|
176
|
+
// Try as number first (1-based index)
|
|
177
|
+
const num = parseInt(ref, 10);
|
|
178
|
+
if (!isNaN(num) && num > 0 && num <= sessions.length) {
|
|
179
|
+
return sessions[num - 1];
|
|
180
|
+
}
|
|
181
|
+
// Try as session ID
|
|
182
|
+
return sessions.find(s => s.id === ref || s.id.startsWith(ref));
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=claude-session-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-session-reader.js","sourceRoot":"","sources":["../../src/core/claude-session-reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { ClaudeUsageQuota } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Processed usage data for display
|
|
4
|
+
*/
|
|
5
|
+
export interface ClaudeUsageStats {
|
|
6
|
+
today: {
|
|
7
|
+
messageCount: number;
|
|
8
|
+
sessionCount: number;
|
|
9
|
+
toolCallCount: number;
|
|
10
|
+
tokensByModel: Record<string, number>;
|
|
11
|
+
};
|
|
12
|
+
week: {
|
|
13
|
+
messageCount: number;
|
|
14
|
+
sessionCount: number;
|
|
15
|
+
toolCallCount: number;
|
|
16
|
+
tokensByModel: Record<string, number>;
|
|
17
|
+
};
|
|
18
|
+
modelUsage: Record<string, {
|
|
19
|
+
inputTokens: number;
|
|
20
|
+
outputTokens: number;
|
|
21
|
+
cacheReadTokens: number;
|
|
22
|
+
cacheCreationTokens: number;
|
|
23
|
+
}>;
|
|
24
|
+
totalSessions: number;
|
|
25
|
+
totalMessages: number;
|
|
26
|
+
firstSessionDate: string | null;
|
|
27
|
+
lastUpdated: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Query Claude Code's local stats cache file.
|
|
31
|
+
* Results are cached for 30 seconds.
|
|
32
|
+
*
|
|
33
|
+
* @param forceRefresh - If true, bypasses the cache
|
|
34
|
+
* @returns Parsed usage stats, or null if unavailable
|
|
35
|
+
*/
|
|
36
|
+
export declare function queryClaudeUsage(forceRefresh?: boolean): Promise<ClaudeUsageStats | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Clear the usage cache.
|
|
39
|
+
*/
|
|
40
|
+
export declare function clearUsageCache(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Check if Claude usage data is available.
|
|
43
|
+
*/
|
|
44
|
+
export declare function hasClaudeUsage(): Promise<boolean>;
|
|
45
|
+
/**
|
|
46
|
+
* Format model name for display (extract short name)
|
|
47
|
+
*/
|
|
48
|
+
export declare function formatModelName(modelId: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* Format token count for display
|
|
51
|
+
*/
|
|
52
|
+
export declare function formatTokenCount(tokens: number): string;
|
|
53
|
+
/**
|
|
54
|
+
* Query Claude usage quota from the Anthropic OAuth API.
|
|
55
|
+
*
|
|
56
|
+
* This calls: GET https://api.anthropic.com/api/oauth/usage
|
|
57
|
+
* Returns the 5-hour and 7-day utilization buckets.
|
|
58
|
+
*
|
|
59
|
+
* @param forceRefresh - If true, bypasses the cache
|
|
60
|
+
*/
|
|
61
|
+
export declare function queryClaudeQuota(forceRefresh?: boolean): Promise<ClaudeUsageQuota | null>;
|
|
62
|
+
/**
|
|
63
|
+
* Clear the quota cache.
|
|
64
|
+
*/
|
|
65
|
+
export declare function clearQuotaCache(): void;
|
|
66
|
+
/**
|
|
67
|
+
* Check if Claude quota data is available.
|
|
68
|
+
*/
|
|
69
|
+
export declare function hasClaudeQuota(): Promise<boolean>;
|
|
70
|
+
/**
|
|
71
|
+
* Format quota percentage for display
|
|
72
|
+
*/
|
|
73
|
+
export declare function formatQuotaPercent(utilization: number): string;
|
|
74
|
+
/**
|
|
75
|
+
* Get time until quota reset in human-readable format
|
|
76
|
+
*/
|
|
77
|
+
export declare function getTimeUntilReset(resetsAt: string): string;
|
|
78
|
+
//# sourceMappingURL=claude-usage-query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-usage-query.d.ts","sourceRoot":"","sources":["../../src/core/claude-usage-query.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAwC/C;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAE/B,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACvC,CAAC;IAEF,IAAI,EAAE;QACJ,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACvC,CAAC;IAEF,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QACzB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,EAAE,MAAM,CAAC;QACxB,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC,CAAC;IAEH,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;CACrB;AA+ED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,YAAY,UAAQ,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA8B7F;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAGvD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKvD;AAiFD;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,YAAY,UAAQ,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA4D7F;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAGvD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAc1D"}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
// Cache for usage data
|
|
5
|
+
let cachedStats = null;
|
|
6
|
+
let cacheTimestamp = 0;
|
|
7
|
+
const CACHE_TTL_MS = 30_000; // 30 seconds cache
|
|
8
|
+
/**
|
|
9
|
+
* Get the path to Claude Code's stats-cache.json file
|
|
10
|
+
*/
|
|
11
|
+
function getStatsCachePath() {
|
|
12
|
+
return join(homedir(), '.claude', 'stats-cache.json');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Parse the stats-cache.json and compute usage stats
|
|
16
|
+
*/
|
|
17
|
+
function parseStatsCache(raw) {
|
|
18
|
+
const now = new Date();
|
|
19
|
+
const todayStr = now.toISOString().split('T')[0];
|
|
20
|
+
// Calculate week start (Sunday)
|
|
21
|
+
const dayOfWeek = now.getDay();
|
|
22
|
+
const weekStart = new Date(now);
|
|
23
|
+
weekStart.setDate(now.getDate() - dayOfWeek);
|
|
24
|
+
weekStart.setHours(0, 0, 0, 0);
|
|
25
|
+
// Today's activity
|
|
26
|
+
const todayActivity = raw.dailyActivity.find(d => d.date === todayStr);
|
|
27
|
+
const todayTokens = raw.dailyModelTokens.find(d => d.date === todayStr);
|
|
28
|
+
// Week's activity (sum of last 7 days from week start)
|
|
29
|
+
const weekActivity = raw.dailyActivity
|
|
30
|
+
.filter(d => new Date(d.date) >= weekStart)
|
|
31
|
+
.reduce((acc, day) => ({
|
|
32
|
+
messageCount: acc.messageCount + day.messageCount,
|
|
33
|
+
sessionCount: acc.sessionCount + day.sessionCount,
|
|
34
|
+
toolCallCount: acc.toolCallCount + day.toolCallCount,
|
|
35
|
+
}), { messageCount: 0, sessionCount: 0, toolCallCount: 0 });
|
|
36
|
+
// Week's tokens by model
|
|
37
|
+
const weekTokensByModel = {};
|
|
38
|
+
raw.dailyModelTokens
|
|
39
|
+
.filter(d => new Date(d.date) >= weekStart)
|
|
40
|
+
.forEach(day => {
|
|
41
|
+
Object.entries(day.tokensByModel).forEach(([model, tokens]) => {
|
|
42
|
+
weekTokensByModel[model] = (weekTokensByModel[model] || 0) + tokens;
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
today: {
|
|
47
|
+
messageCount: todayActivity?.messageCount || 0,
|
|
48
|
+
sessionCount: todayActivity?.sessionCount || 0,
|
|
49
|
+
toolCallCount: todayActivity?.toolCallCount || 0,
|
|
50
|
+
tokensByModel: todayTokens?.tokensByModel || {},
|
|
51
|
+
},
|
|
52
|
+
week: {
|
|
53
|
+
...weekActivity,
|
|
54
|
+
tokensByModel: weekTokensByModel,
|
|
55
|
+
},
|
|
56
|
+
modelUsage: Object.fromEntries(Object.entries(raw.modelUsage).map(([model, usage]) => [
|
|
57
|
+
model,
|
|
58
|
+
{
|
|
59
|
+
inputTokens: usage.inputTokens,
|
|
60
|
+
outputTokens: usage.outputTokens,
|
|
61
|
+
cacheReadTokens: usage.cacheReadInputTokens,
|
|
62
|
+
cacheCreationTokens: usage.cacheCreationInputTokens,
|
|
63
|
+
},
|
|
64
|
+
])),
|
|
65
|
+
totalSessions: raw.totalSessions,
|
|
66
|
+
totalMessages: raw.totalMessages,
|
|
67
|
+
firstSessionDate: raw.firstSessionDate || null,
|
|
68
|
+
lastUpdated: new Date().toISOString(),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Query Claude Code's local stats cache file.
|
|
73
|
+
* Results are cached for 30 seconds.
|
|
74
|
+
*
|
|
75
|
+
* @param forceRefresh - If true, bypasses the cache
|
|
76
|
+
* @returns Parsed usage stats, or null if unavailable
|
|
77
|
+
*/
|
|
78
|
+
export async function queryClaudeUsage(forceRefresh = false) {
|
|
79
|
+
const now = Date.now();
|
|
80
|
+
// Return cached data if still valid
|
|
81
|
+
if (!forceRefresh && cachedStats && (now - cacheTimestamp) < CACHE_TTL_MS) {
|
|
82
|
+
return cachedStats;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const statsPath = getStatsCachePath();
|
|
86
|
+
if (!existsSync(statsPath)) {
|
|
87
|
+
console.log('[claude-usage-query] Stats cache file not found:', statsPath);
|
|
88
|
+
return cachedStats; // Return stale cache if available
|
|
89
|
+
}
|
|
90
|
+
const content = readFileSync(statsPath, 'utf-8');
|
|
91
|
+
const raw = JSON.parse(content);
|
|
92
|
+
const parsed = parseStatsCache(raw);
|
|
93
|
+
cachedStats = parsed;
|
|
94
|
+
cacheTimestamp = now;
|
|
95
|
+
return parsed;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (error instanceof Error) {
|
|
99
|
+
console.log('[claude-usage-query] Error reading stats cache:', error.message);
|
|
100
|
+
}
|
|
101
|
+
return cachedStats; // Return stale cache if available
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Clear the usage cache.
|
|
106
|
+
*/
|
|
107
|
+
export function clearUsageCache() {
|
|
108
|
+
cacheTimestamp = 0;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Check if Claude usage data is available.
|
|
112
|
+
*/
|
|
113
|
+
export async function hasClaudeUsage() {
|
|
114
|
+
const stats = await queryClaudeUsage();
|
|
115
|
+
return stats !== null;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Format model name for display (extract short name)
|
|
119
|
+
*/
|
|
120
|
+
export function formatModelName(modelId) {
|
|
121
|
+
if (modelId.includes('opus'))
|
|
122
|
+
return 'Opus';
|
|
123
|
+
if (modelId.includes('sonnet'))
|
|
124
|
+
return 'Sonnet';
|
|
125
|
+
if (modelId.includes('haiku'))
|
|
126
|
+
return 'Haiku';
|
|
127
|
+
return modelId.split('-').slice(1, 3).join(' ');
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Format token count for display
|
|
131
|
+
*/
|
|
132
|
+
export function formatTokenCount(tokens) {
|
|
133
|
+
if (tokens < 1000)
|
|
134
|
+
return tokens.toString();
|
|
135
|
+
if (tokens < 1_000_000)
|
|
136
|
+
return `${(tokens / 1000).toFixed(1)}K`;
|
|
137
|
+
if (tokens < 1_000_000_000)
|
|
138
|
+
return `${(tokens / 1_000_000).toFixed(1)}M`;
|
|
139
|
+
return `${(tokens / 1_000_000_000).toFixed(2)}B`;
|
|
140
|
+
}
|
|
141
|
+
// ============================================================================
|
|
142
|
+
// Claude OAuth Quota API
|
|
143
|
+
// ============================================================================
|
|
144
|
+
// Cache for quota data
|
|
145
|
+
let cachedQuota = null;
|
|
146
|
+
let quotaCacheTimestamp = 0;
|
|
147
|
+
const QUOTA_CACHE_TTL_MS = 60_000; // 1 minute cache
|
|
148
|
+
/**
|
|
149
|
+
* Get Claude Code OAuth token from local storage.
|
|
150
|
+
*
|
|
151
|
+
* Claude Code stores credentials in ~/.claude/.credentials.json
|
|
152
|
+
* under the 'claudeAiOauth' key.
|
|
153
|
+
*/
|
|
154
|
+
async function getClaudeOAuthToken() {
|
|
155
|
+
// Primary location: ~/.claude/.credentials.json
|
|
156
|
+
const credentialsPath = join(homedir(), '.claude', '.credentials.json');
|
|
157
|
+
if (existsSync(credentialsPath)) {
|
|
158
|
+
try {
|
|
159
|
+
const content = readFileSync(credentialsPath, 'utf-8');
|
|
160
|
+
const creds = JSON.parse(content);
|
|
161
|
+
if (creds.claudeAiOauth?.accessToken) {
|
|
162
|
+
// Check if token is expired
|
|
163
|
+
if (creds.claudeAiOauth.expiresAt) {
|
|
164
|
+
const expiresAt = new Date(creds.claudeAiOauth.expiresAt);
|
|
165
|
+
if (expiresAt <= new Date()) {
|
|
166
|
+
console.log('[claude-usage-query] OAuth token is expired');
|
|
167
|
+
// Token is expired, but we'll still try it - the API will tell us for sure
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
console.log('[claude-usage-query] Found token in .credentials.json');
|
|
171
|
+
return creds.claudeAiOauth.accessToken;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
console.log('[claude-usage-query] Error reading .credentials.json:', error);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Fallback: Check for older credentials.json format (without dot prefix)
|
|
179
|
+
const oldCredentialsPath = join(homedir(), '.claude', 'credentials.json');
|
|
180
|
+
if (existsSync(oldCredentialsPath)) {
|
|
181
|
+
try {
|
|
182
|
+
const content = readFileSync(oldCredentialsPath, 'utf-8');
|
|
183
|
+
const creds = JSON.parse(content);
|
|
184
|
+
// Try both formats
|
|
185
|
+
const token = creds.claudeAiOauth?.accessToken || creds.accessToken;
|
|
186
|
+
if (token) {
|
|
187
|
+
console.log('[claude-usage-query] Found token in credentials.json (legacy)');
|
|
188
|
+
return token;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
console.log('[claude-usage-query] Error reading credentials.json:', error);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
console.log('[claude-usage-query] No OAuth token found in', credentialsPath);
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Query Claude usage quota from the Anthropic OAuth API.
|
|
200
|
+
*
|
|
201
|
+
* This calls: GET https://api.anthropic.com/api/oauth/usage
|
|
202
|
+
* Returns the 5-hour and 7-day utilization buckets.
|
|
203
|
+
*
|
|
204
|
+
* @param forceRefresh - If true, bypasses the cache
|
|
205
|
+
*/
|
|
206
|
+
export async function queryClaudeQuota(forceRefresh = false) {
|
|
207
|
+
const now = Date.now();
|
|
208
|
+
// Return cached data if still valid
|
|
209
|
+
if (!forceRefresh && cachedQuota && (now - quotaCacheTimestamp) < QUOTA_CACHE_TTL_MS) {
|
|
210
|
+
return cachedQuota;
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
const token = await getClaudeOAuthToken();
|
|
214
|
+
if (!token) {
|
|
215
|
+
console.log('[claude-usage-query] No OAuth token available for quota query');
|
|
216
|
+
return cachedQuota; // Return stale cache if available
|
|
217
|
+
}
|
|
218
|
+
const response = await fetch('https://api.anthropic.com/api/oauth/usage', {
|
|
219
|
+
method: 'GET',
|
|
220
|
+
headers: {
|
|
221
|
+
'Authorization': `Bearer ${token}`,
|
|
222
|
+
'anthropic-beta': 'oauth-2025-04-20',
|
|
223
|
+
'Accept': 'application/json',
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
if (!response.ok) {
|
|
227
|
+
const errorText = await response.text();
|
|
228
|
+
console.log(`[claude-usage-query] Quota API error (${response.status}):`, errorText);
|
|
229
|
+
return cachedQuota; // Return stale cache
|
|
230
|
+
}
|
|
231
|
+
const data = await response.json();
|
|
232
|
+
// Parse the response - API returns utilization as 0-100, we normalize to 0-1
|
|
233
|
+
const quota = {
|
|
234
|
+
five_hour: {
|
|
235
|
+
utilization: (data.five_hour?.utilization ?? 0) / 100,
|
|
236
|
+
resets_at: data.five_hour?.resets_at ?? new Date().toISOString(),
|
|
237
|
+
},
|
|
238
|
+
seven_day: {
|
|
239
|
+
utilization: (data.seven_day?.utilization ?? 0) / 100,
|
|
240
|
+
resets_at: data.seven_day?.resets_at ?? new Date().toISOString(),
|
|
241
|
+
},
|
|
242
|
+
lastUpdated: new Date().toISOString(),
|
|
243
|
+
};
|
|
244
|
+
cachedQuota = quota;
|
|
245
|
+
quotaCacheTimestamp = now;
|
|
246
|
+
console.log('[claude-usage-query] Quota fetched successfully:', {
|
|
247
|
+
fiveHour: `${(quota.five_hour.utilization * 100).toFixed(1)}%`,
|
|
248
|
+
sevenDay: `${(quota.seven_day.utilization * 100).toFixed(1)}%`,
|
|
249
|
+
});
|
|
250
|
+
return quota;
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
if (error instanceof Error) {
|
|
254
|
+
console.log('[claude-usage-query] Error fetching quota:', error.message);
|
|
255
|
+
}
|
|
256
|
+
return cachedQuota; // Return stale cache if available
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Clear the quota cache.
|
|
261
|
+
*/
|
|
262
|
+
export function clearQuotaCache() {
|
|
263
|
+
quotaCacheTimestamp = 0;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Check if Claude quota data is available.
|
|
267
|
+
*/
|
|
268
|
+
export async function hasClaudeQuota() {
|
|
269
|
+
const quota = await queryClaudeQuota();
|
|
270
|
+
return quota !== null;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Format quota percentage for display
|
|
274
|
+
*/
|
|
275
|
+
export function formatQuotaPercent(utilization) {
|
|
276
|
+
return `${(utilization * 100).toFixed(1)}%`;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Get time until quota reset in human-readable format
|
|
280
|
+
*/
|
|
281
|
+
export function getTimeUntilReset(resetsAt) {
|
|
282
|
+
const now = new Date();
|
|
283
|
+
const resetTime = new Date(resetsAt);
|
|
284
|
+
const diffMs = resetTime.getTime() - now.getTime();
|
|
285
|
+
if (diffMs <= 0)
|
|
286
|
+
return 'now';
|
|
287
|
+
const hours = Math.floor(diffMs / (1000 * 60 * 60));
|
|
288
|
+
const minutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
|
|
289
|
+
if (hours > 0) {
|
|
290
|
+
return `${hours}h ${minutes}m`;
|
|
291
|
+
}
|
|
292
|
+
return `${minutes}m`;
|
|
293
|
+
}
|
|
294
|
+
//# sourceMappingURL=claude-usage-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-usage-query.js","sourceRoot":"","sources":["../../src/core/claude-usage-query.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a temporary credential helper script that returns the OAuth token.
|
|
3
|
+
* The script is compatible with git's credential helper protocol.
|
|
4
|
+
* @param token - The OAuth access token
|
|
5
|
+
* @param platform - The git platform ('github' or 'gitlab')
|
|
6
|
+
* @returns Path to the temporary credential helper script
|
|
7
|
+
*/
|
|
8
|
+
export declare function createCredentialHelperScript(token: string, platform: 'github' | 'gitlab'): string;
|
|
9
|
+
/**
|
|
10
|
+
* Removes a temporary credential helper script.
|
|
11
|
+
* SEC-06: Improved cleanup with logging for debugging failed deletions.
|
|
12
|
+
* @param scriptPath - Path to the script to remove
|
|
13
|
+
*/
|
|
14
|
+
export declare function removeCredentialHelperScript(scriptPath: string): void;
|
|
15
|
+
/**
|
|
16
|
+
* Get environment variables to inject for git authentication.
|
|
17
|
+
* These environment variables enable git to use the OAuth token for HTTPS operations.
|
|
18
|
+
*
|
|
19
|
+
* @param token - The OAuth access token
|
|
20
|
+
* @param platform - The git platform ('github' or 'gitlab')
|
|
21
|
+
* @param username - Optional username (defaults based on platform)
|
|
22
|
+
* @returns Record of environment variables to set
|
|
23
|
+
*/
|
|
24
|
+
export declare function getGitCredentialEnv(token: string, platform: 'github' | 'gitlab', username?: string): Record<string, string>;
|
|
25
|
+
/**
|
|
26
|
+
* Clean up any temporary files created by getGitCredentialEnv.
|
|
27
|
+
* Call this after git operations complete.
|
|
28
|
+
*
|
|
29
|
+
* @param env - The environment object returned by getGitCredentialEnv
|
|
30
|
+
*/
|
|
31
|
+
export declare function cleanupGitCredentialEnv(env: Record<string, string>): void;
|
|
32
|
+
/**
|
|
33
|
+
* Configure git to use token authentication for a specific remote URL.
|
|
34
|
+
* This modifies the URL to include the token inline (for temporary use).
|
|
35
|
+
*
|
|
36
|
+
* @param remoteUrl - The original remote URL (e.g., https://github.com/user/repo.git)
|
|
37
|
+
* @param token - The OAuth access token
|
|
38
|
+
* @param platform - The git platform
|
|
39
|
+
* @returns The modified URL with embedded credentials
|
|
40
|
+
*/
|
|
41
|
+
export declare function getAuthenticatedRemoteUrl(remoteUrl: string, token: string, platform: 'github' | 'gitlab'): string;
|
|
42
|
+
/**
|
|
43
|
+
* Detect the git platform from a remote URL.
|
|
44
|
+
*
|
|
45
|
+
* @param remoteUrl - The remote URL to analyze
|
|
46
|
+
* @returns 'github', 'gitlab', or null if unknown
|
|
47
|
+
*/
|
|
48
|
+
export declare function detectPlatformFromUrl(remoteUrl: string): 'github' | 'gitlab' | null;
|
|
49
|
+
/**
|
|
50
|
+
* Check if a remote URL is using HTTPS (vs SSH).
|
|
51
|
+
* OAuth tokens only work with HTTPS remotes.
|
|
52
|
+
*
|
|
53
|
+
* @param remoteUrl - The remote URL to check
|
|
54
|
+
* @returns true if the URL is HTTPS
|
|
55
|
+
*/
|
|
56
|
+
export declare function isHttpsRemote(remoteUrl: string): boolean;
|
|
57
|
+
//# sourceMappingURL=git-credential-helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-credential-helper.d.ts","sourceRoot":"","sources":["../../src/core/git-credential-helper.ts"],"names":[],"mappings":"AAiBA;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAkCjG;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAerE;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,GAAG,QAAQ,EAC7B,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA8BxB;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAKzE;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAC5B,MAAM,CAgBR;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAYnF;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAExD"}
|