@codemieai/code 0.0.11 → 0.0.13
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/README.md +70 -861
- package/dist/agents/codemie-code/agent.d.ts.map +1 -1
- package/dist/agents/codemie-code/agent.js +35 -4
- package/dist/agents/codemie-code/agent.js.map +1 -1
- package/dist/agents/codemie-code/tools/index.d.ts.map +1 -1
- package/dist/agents/codemie-code/tools/index.js +5 -3
- package/dist/agents/codemie-code/tools/index.js.map +1 -1
- package/dist/agents/core/AgentCLI.d.ts.map +1 -1
- package/dist/agents/core/AgentCLI.js +57 -11
- package/dist/agents/core/AgentCLI.js.map +1 -1
- package/dist/agents/core/BaseAgentAdapter.d.ts +4 -4
- package/dist/agents/core/BaseAgentAdapter.d.ts.map +1 -1
- package/dist/agents/core/BaseAgentAdapter.js +59 -23
- package/dist/agents/core/BaseAgentAdapter.js.map +1 -1
- package/dist/agents/core/types.d.ts +18 -0
- package/dist/agents/core/types.d.ts.map +1 -1
- package/dist/agents/plugins/claude.plugin.d.ts +0 -3
- package/dist/agents/plugins/claude.plugin.d.ts.map +1 -1
- package/dist/agents/plugins/claude.plugin.js +12 -1
- package/dist/agents/plugins/claude.plugin.js.map +1 -1
- package/dist/agents/plugins/codemie-code.plugin.js +1 -1
- package/dist/agents/plugins/codemie-code.plugin.js.map +1 -1
- package/dist/agents/plugins/codex.plugin.d.ts.map +1 -1
- package/dist/agents/plugins/codex.plugin.js +40 -4
- package/dist/agents/plugins/codex.plugin.js.map +1 -1
- package/dist/agents/plugins/gemini.plugin.d.ts.map +1 -1
- package/dist/agents/plugins/gemini.plugin.js +51 -6
- package/dist/agents/plugins/gemini.plugin.js.map +1 -1
- package/dist/agents/registry.d.ts +15 -2
- package/dist/agents/registry.d.ts.map +1 -1
- package/dist/agents/registry.js +30 -6
- package/dist/agents/registry.js.map +1 -1
- package/dist/analytics/aggregation/adapters/claude.adapter.d.ts +37 -0
- package/dist/analytics/aggregation/adapters/claude.adapter.d.ts.map +1 -0
- package/dist/analytics/aggregation/adapters/claude.adapter.js +471 -0
- package/dist/analytics/aggregation/adapters/claude.adapter.js.map +1 -0
- package/dist/analytics/aggregation/adapters/codex.adapter.d.ts +25 -0
- package/dist/analytics/aggregation/adapters/codex.adapter.d.ts.map +1 -0
- package/dist/analytics/aggregation/adapters/codex.adapter.js +376 -0
- package/dist/analytics/aggregation/adapters/codex.adapter.js.map +1 -0
- package/dist/analytics/aggregation/adapters/gemini.adapter.d.ts +28 -0
- package/dist/analytics/aggregation/adapters/gemini.adapter.d.ts.map +1 -0
- package/dist/analytics/aggregation/adapters/gemini.adapter.js +320 -0
- package/dist/analytics/aggregation/adapters/gemini.adapter.js.map +1 -0
- package/dist/analytics/aggregation/adapters/index.d.ts +7 -0
- package/dist/analytics/aggregation/adapters/index.d.ts.map +1 -0
- package/dist/analytics/aggregation/adapters/index.js +7 -0
- package/dist/analytics/aggregation/adapters/index.js.map +1 -0
- package/dist/analytics/aggregation/aggregator.d.ts +49 -0
- package/dist/analytics/aggregation/aggregator.d.ts.map +1 -0
- package/dist/analytics/aggregation/aggregator.js +239 -0
- package/dist/analytics/aggregation/aggregator.js.map +1 -0
- package/dist/analytics/aggregation/core/BaseAnalyticsAdapter.d.ts +63 -0
- package/dist/analytics/aggregation/core/BaseAnalyticsAdapter.d.ts.map +1 -0
- package/dist/analytics/aggregation/core/BaseAnalyticsAdapter.js +58 -0
- package/dist/analytics/aggregation/core/BaseAnalyticsAdapter.js.map +1 -0
- package/dist/analytics/aggregation/core/adapter.interface.d.ts +65 -0
- package/dist/analytics/aggregation/core/adapter.interface.d.ts.map +1 -0
- package/dist/analytics/aggregation/core/adapter.interface.js +9 -0
- package/dist/analytics/aggregation/core/adapter.interface.js.map +1 -0
- package/dist/analytics/aggregation/core/aggregation-utils.d.ts +66 -0
- package/dist/analytics/aggregation/core/aggregation-utils.d.ts.map +1 -0
- package/dist/analytics/aggregation/core/aggregation-utils.js +83 -0
- package/dist/analytics/aggregation/core/aggregation-utils.js.map +1 -0
- package/dist/analytics/aggregation/core/discovery.d.ts +40 -0
- package/dist/analytics/aggregation/core/discovery.d.ts.map +1 -0
- package/dist/analytics/aggregation/core/discovery.js +132 -0
- package/dist/analytics/aggregation/core/discovery.js.map +1 -0
- package/dist/analytics/aggregation/core/file-utils.d.ts +23 -0
- package/dist/analytics/aggregation/core/file-utils.d.ts.map +1 -0
- package/dist/analytics/aggregation/core/file-utils.js +208 -0
- package/dist/analytics/aggregation/core/file-utils.js.map +1 -0
- package/dist/analytics/aggregation/core/index.d.ts +11 -0
- package/dist/analytics/aggregation/core/index.d.ts.map +1 -0
- package/dist/analytics/aggregation/core/index.js +11 -0
- package/dist/analytics/aggregation/core/index.js.map +1 -0
- package/dist/analytics/aggregation/core/project-mapping.d.ts +50 -0
- package/dist/analytics/aggregation/core/project-mapping.d.ts.map +1 -0
- package/dist/analytics/aggregation/core/project-mapping.js +102 -0
- package/dist/analytics/aggregation/core/project-mapping.js.map +1 -0
- package/dist/analytics/aggregation/core/streaming.d.ts +26 -0
- package/dist/analytics/aggregation/core/streaming.d.ts.map +1 -0
- package/dist/analytics/aggregation/core/streaming.js +58 -0
- package/dist/analytics/aggregation/core/streaming.js.map +1 -0
- package/dist/analytics/aggregation/index.d.ts +8 -0
- package/dist/analytics/aggregation/index.d.ts.map +1 -0
- package/dist/analytics/aggregation/index.js +8 -0
- package/dist/analytics/aggregation/index.js.map +1 -0
- package/dist/analytics/aggregation/types.d.ts +258 -0
- package/dist/analytics/aggregation/types.d.ts.map +1 -0
- package/dist/analytics/aggregation/types.js +8 -0
- package/dist/analytics/aggregation/types.js.map +1 -0
- package/dist/analytics/collector.d.ts +46 -0
- package/dist/analytics/collector.d.ts.map +1 -0
- package/dist/analytics/collector.js +83 -0
- package/dist/analytics/collector.js.map +1 -0
- package/dist/analytics/config.d.ts +15 -0
- package/dist/analytics/config.d.ts.map +1 -0
- package/dist/analytics/config.js +65 -0
- package/dist/analytics/config.js.map +1 -0
- package/dist/analytics/index.d.ts +99 -0
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/index.js +288 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/plugins/api-metrics.plugin.d.ts +26 -0
- package/dist/analytics/plugins/api-metrics.plugin.d.ts.map +1 -0
- package/dist/analytics/plugins/api-metrics.plugin.js +97 -0
- package/dist/analytics/plugins/api-metrics.plugin.js.map +1 -0
- package/dist/analytics/plugins/index.d.ts +15 -0
- package/dist/analytics/plugins/index.d.ts.map +1 -0
- package/dist/analytics/plugins/index.js +15 -0
- package/dist/analytics/plugins/index.js.map +1 -0
- package/dist/analytics/plugins/model-metrics.plugin.d.ts +39 -0
- package/dist/analytics/plugins/model-metrics.plugin.d.ts.map +1 -0
- package/dist/analytics/plugins/model-metrics.plugin.js +105 -0
- package/dist/analytics/plugins/model-metrics.plugin.js.map +1 -0
- package/dist/analytics/plugins/provider-metrics.plugin.d.ts +41 -0
- package/dist/analytics/plugins/provider-metrics.plugin.d.ts.map +1 -0
- package/dist/analytics/plugins/provider-metrics.plugin.js +123 -0
- package/dist/analytics/plugins/provider-metrics.plugin.js.map +1 -0
- package/dist/analytics/plugins/types.d.ts +61 -0
- package/dist/analytics/plugins/types.d.ts.map +1 -0
- package/dist/analytics/plugins/types.js +54 -0
- package/dist/analytics/plugins/types.js.map +1 -0
- package/dist/analytics/privacy.d.ts +10 -0
- package/dist/analytics/privacy.d.ts.map +1 -0
- package/dist/analytics/privacy.js +20 -0
- package/dist/analytics/privacy.js.map +1 -0
- package/dist/analytics/session.d.ts +56 -0
- package/dist/analytics/session.d.ts.map +1 -0
- package/dist/analytics/session.js +95 -0
- package/dist/analytics/session.js.map +1 -0
- package/dist/analytics/types.d.ts +104 -0
- package/dist/analytics/types.d.ts.map +1 -0
- package/dist/analytics/types.js +15 -0
- package/dist/analytics/types.js.map +1 -0
- package/dist/analytics/writer.d.ts +18 -0
- package/dist/analytics/writer.d.ts.map +1 -0
- package/dist/analytics/writer.js +44 -0
- package/dist/analytics/writer.js.map +1 -0
- package/dist/cli/commands/analytics.d.ts +3 -0
- package/dist/cli/commands/analytics.d.ts.map +1 -0
- package/dist/cli/commands/analytics.js +579 -0
- package/dist/cli/commands/analytics.js.map +1 -0
- package/dist/cli/commands/config.d.ts.map +1 -1
- package/dist/cli/commands/config.js +14 -0
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/profile.d.ts.map +1 -1
- package/dist/cli/commands/profile.js +41 -0
- package/dist/cli/commands/profile.js.map +1 -1
- package/dist/cli/commands/setup.js +70 -1
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/env/types.d.ts +2 -0
- package/dist/env/types.d.ts.map +1 -1
- package/dist/env/types.js.map +1 -1
- package/dist/utils/analytics-reader.d.ts +117 -0
- package/dist/utils/analytics-reader.d.ts.map +1 -0
- package/dist/utils/analytics-reader.js +421 -0
- package/dist/utils/analytics-reader.js.map +1 -0
- package/dist/utils/codemie-integration-validator.d.ts.map +1 -1
- package/dist/utils/codemie-integration-validator.js +3 -16
- package/dist/utils/codemie-integration-validator.js.map +1 -1
- package/dist/utils/codemie-proxy.d.ts +80 -0
- package/dist/utils/codemie-proxy.d.ts.map +1 -0
- package/dist/utils/codemie-proxy.js +348 -0
- package/dist/utils/codemie-proxy.js.map +1 -0
- package/dist/utils/config-loader.d.ts +7 -0
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +18 -0
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/date-formatter.d.ts +88 -0
- package/dist/utils/date-formatter.d.ts.map +1 -0
- package/dist/utils/date-formatter.js +133 -0
- package/dist/utils/date-formatter.js.map +1 -0
- package/dist/utils/installation-id.d.ts +10 -0
- package/dist/utils/installation-id.d.ts.map +1 -0
- package/dist/utils/installation-id.js +30 -0
- package/dist/utils/installation-id.js.map +1 -0
- package/dist/utils/logger.d.ts +1 -15
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +5 -86
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/proxy/errors.d.ts +45 -0
- package/dist/utils/proxy/errors.d.ts.map +1 -0
- package/dist/utils/proxy/errors.js +103 -0
- package/dist/utils/proxy/errors.js.map +1 -0
- package/dist/utils/proxy/http-client.d.ts +46 -0
- package/dist/utils/proxy/http-client.d.ts.map +1 -0
- package/dist/utils/proxy/http-client.js +139 -0
- package/dist/utils/proxy/http-client.js.map +1 -0
- package/dist/utils/proxy/interceptors.d.ts +69 -0
- package/dist/utils/proxy/interceptors.d.ts.map +1 -0
- package/dist/utils/proxy/interceptors.js +308 -0
- package/dist/utils/proxy/interceptors.js.map +1 -0
- package/dist/utils/proxy/types.d.ts +45 -0
- package/dist/utils/proxy/types.d.ts.map +1 -0
- package/dist/utils/proxy/types.js +7 -0
- package/dist/utils/proxy/types.js.map +1 -0
- package/package.json +43 -6
- package/dist/utils/sso-gateway.d.ts +0 -75
- package/dist/utils/sso-gateway.d.ts.map +0 -1
- package/dist/utils/sso-gateway.js +0 -453
- package/dist/utils/sso-gateway.js.map +0 -1
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini CLI Analytics Adapter
|
|
3
|
+
*
|
|
4
|
+
* Extracts analytics data from Gemini CLI session files stored in:
|
|
5
|
+
* ~/.gemini/tmp/{projectHash}/chats/session-{timestamp}-{id}.json
|
|
6
|
+
*/
|
|
7
|
+
import { join, extname } from 'node:path';
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
import { BaseAnalyticsAdapter, resolvePath, findFiles, filterFilesByDate, readJSON, detectLanguage, detectFormat, countLines, calculateByteSize, calculateFileStats, resolveProjectPath } from '../core/index.js';
|
|
10
|
+
/**
|
|
11
|
+
* Gemini CLI analytics adapter
|
|
12
|
+
*/
|
|
13
|
+
export class GeminiAnalyticsAdapter extends BaseAnalyticsAdapter {
|
|
14
|
+
constructor(metadata) {
|
|
15
|
+
super(metadata);
|
|
16
|
+
}
|
|
17
|
+
async findSessions(options) {
|
|
18
|
+
const baseDir = resolvePath(this.homePath);
|
|
19
|
+
const tmpDir = join(baseDir, 'tmp');
|
|
20
|
+
if (!existsSync(tmpDir)) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
const descriptors = [];
|
|
24
|
+
// Scan all project hash directories
|
|
25
|
+
const { readdir } = await import('node:fs/promises');
|
|
26
|
+
try {
|
|
27
|
+
const projectDirs = await readdir(tmpDir, { withFileTypes: true });
|
|
28
|
+
for (const projectDir of projectDirs) {
|
|
29
|
+
if (!projectDir.isDirectory())
|
|
30
|
+
continue;
|
|
31
|
+
const chatsDir = join(tmpDir, projectDir.name, 'chats');
|
|
32
|
+
if (!existsSync(chatsDir))
|
|
33
|
+
continue;
|
|
34
|
+
// Find all session files
|
|
35
|
+
const sessionFiles = await findFiles(chatsDir, /^session-.*\.json$/);
|
|
36
|
+
// Filter by date if specified
|
|
37
|
+
let filteredFiles = sessionFiles;
|
|
38
|
+
if (options?.dateFrom || options?.dateTo) {
|
|
39
|
+
filteredFiles = await filterFilesByDate(sessionFiles, options.dateFrom, options.dateTo);
|
|
40
|
+
}
|
|
41
|
+
// Create descriptors
|
|
42
|
+
for (const filePath of filteredFiles) {
|
|
43
|
+
try {
|
|
44
|
+
const session = await readJSON(filePath);
|
|
45
|
+
descriptors.push({
|
|
46
|
+
sessionId: session.sessionId,
|
|
47
|
+
agent: this.agentName,
|
|
48
|
+
filePaths: [filePath],
|
|
49
|
+
metadata: {
|
|
50
|
+
projectHash: session.projectHash,
|
|
51
|
+
startTime: session.startTime,
|
|
52
|
+
lastUpdated: session.lastUpdated
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
console.error(`Failed to read session file ${filePath}: ${error}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.error(`Error scanning Gemini sessions: ${error}`);
|
|
64
|
+
}
|
|
65
|
+
// Apply pagination using inherited method
|
|
66
|
+
return this.applyPagination(descriptors, options);
|
|
67
|
+
}
|
|
68
|
+
async extractSession(descriptor) {
|
|
69
|
+
const filePath = descriptor.filePaths[0];
|
|
70
|
+
const session = await readJSON(filePath);
|
|
71
|
+
// Count messages by type
|
|
72
|
+
const userMessages = session.messages.filter(m => m.type === 'user');
|
|
73
|
+
const assistantMessages = session.messages.filter(m => m.type === 'gemini');
|
|
74
|
+
// Count tool calls and their statuses, track usage by tool name
|
|
75
|
+
let totalToolCalls = 0;
|
|
76
|
+
let successfulToolCalls = 0;
|
|
77
|
+
let failedToolCalls = 0;
|
|
78
|
+
const toolUsage = {};
|
|
79
|
+
const toolStatus = {};
|
|
80
|
+
for (const message of session.messages) {
|
|
81
|
+
if (message.toolCalls) {
|
|
82
|
+
totalToolCalls += message.toolCalls.length;
|
|
83
|
+
successfulToolCalls += message.toolCalls.filter(tc => tc.status === 'success').length;
|
|
84
|
+
failedToolCalls += message.toolCalls.filter(tc => tc.status === 'failure').length;
|
|
85
|
+
// Track tool usage and status
|
|
86
|
+
for (const tc of message.toolCalls) {
|
|
87
|
+
toolUsage[tc.name] = (toolUsage[tc.name] || 0) + 1;
|
|
88
|
+
// Track success/failure per tool
|
|
89
|
+
if (!toolStatus[tc.name]) {
|
|
90
|
+
toolStatus[tc.name] = { success: 0, failure: 0 };
|
|
91
|
+
}
|
|
92
|
+
if (tc.status === 'success') {
|
|
93
|
+
toolStatus[tc.name].success++;
|
|
94
|
+
}
|
|
95
|
+
else if (tc.status === 'failure') {
|
|
96
|
+
toolStatus[tc.name].failure++;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Track model usage (count messages per model)
|
|
102
|
+
const modelUsage = {};
|
|
103
|
+
for (const message of session.messages) {
|
|
104
|
+
if (message.model) {
|
|
105
|
+
modelUsage[message.model] = (modelUsage[message.model] || 0) + 1;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Count file modifications (tool calls with write/edit operations)
|
|
109
|
+
const fileModifications = await this.extractFileModifications(descriptor);
|
|
110
|
+
// Sum tokens with detailed breakdown
|
|
111
|
+
let totalInputTokens = 0;
|
|
112
|
+
let totalOutputTokens = 0;
|
|
113
|
+
let totalCachedTokens = 0;
|
|
114
|
+
let totalThoughtsTokens = 0;
|
|
115
|
+
let totalToolTokens = 0;
|
|
116
|
+
let totalTokens = 0;
|
|
117
|
+
for (const message of session.messages) {
|
|
118
|
+
if (message.tokens) {
|
|
119
|
+
totalInputTokens += message.tokens.input || 0;
|
|
120
|
+
totalOutputTokens += message.tokens.output || 0;
|
|
121
|
+
totalCachedTokens += message.tokens.cached || 0;
|
|
122
|
+
totalThoughtsTokens += message.tokens.thoughts || 0;
|
|
123
|
+
totalToolTokens += message.tokens.tool || 0;
|
|
124
|
+
totalTokens += message.tokens.total || 0;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Calculate duration
|
|
128
|
+
const startTime = new Date(session.startTime);
|
|
129
|
+
const endTime = new Date(session.lastUpdated);
|
|
130
|
+
const durationMs = endTime.getTime() - startTime.getTime();
|
|
131
|
+
// Check for errors
|
|
132
|
+
const hadErrors = failedToolCalls > 0;
|
|
133
|
+
// Extract model (from first assistant message)
|
|
134
|
+
const model = assistantMessages.find(m => m.model)?.model || 'gemini-2.5-pro';
|
|
135
|
+
// Calculate file statistics using shared utility
|
|
136
|
+
const fileStats = calculateFileStats(fileModifications);
|
|
137
|
+
// Resolve project path from hash using mapping file
|
|
138
|
+
// Mapping file: ~/.codemie/gemini-project-mappings.json
|
|
139
|
+
const projectPath = descriptor.metadata.projectPath ||
|
|
140
|
+
(session.projectHash ? resolveProjectPath('gemini', session.projectHash) : '');
|
|
141
|
+
return {
|
|
142
|
+
sessionId: session.sessionId,
|
|
143
|
+
agent: 'gemini',
|
|
144
|
+
agentVersion: '1.0.0',
|
|
145
|
+
startTime,
|
|
146
|
+
endTime,
|
|
147
|
+
durationMs,
|
|
148
|
+
projectPath,
|
|
149
|
+
projectHash: session.projectHash,
|
|
150
|
+
model,
|
|
151
|
+
provider: 'gemini',
|
|
152
|
+
userMessageCount: userMessages.length,
|
|
153
|
+
assistantMessageCount: assistantMessages.length,
|
|
154
|
+
toolCallCount: totalToolCalls,
|
|
155
|
+
successfulToolCalls,
|
|
156
|
+
failedToolCalls,
|
|
157
|
+
fileModifications: fileModifications.length,
|
|
158
|
+
toolUsage,
|
|
159
|
+
toolStatus,
|
|
160
|
+
modelUsage,
|
|
161
|
+
tokens: {
|
|
162
|
+
input: totalInputTokens,
|
|
163
|
+
output: totalOutputTokens,
|
|
164
|
+
cacheRead: totalCachedTokens,
|
|
165
|
+
cacheCreation: 0, // Gemini uses 'cached' for cache reads, not creation
|
|
166
|
+
thoughts: totalThoughtsTokens,
|
|
167
|
+
tool: totalToolTokens,
|
|
168
|
+
total: totalTokens
|
|
169
|
+
},
|
|
170
|
+
hadErrors,
|
|
171
|
+
fileStats
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
async extractMessages(descriptor) {
|
|
175
|
+
const filePath = descriptor.filePaths[0];
|
|
176
|
+
const session = await readJSON(filePath);
|
|
177
|
+
return session.messages.map(msg => ({
|
|
178
|
+
messageId: msg.id,
|
|
179
|
+
sessionId: session.sessionId,
|
|
180
|
+
timestamp: new Date(msg.timestamp),
|
|
181
|
+
role: msg.type === 'user' ? 'user' : 'assistant',
|
|
182
|
+
content: msg.content,
|
|
183
|
+
tokens: msg.tokens ? {
|
|
184
|
+
input: msg.tokens.input,
|
|
185
|
+
output: msg.tokens.output,
|
|
186
|
+
cacheRead: msg.tokens.cached,
|
|
187
|
+
cacheCreation: 0,
|
|
188
|
+
thoughts: msg.tokens.thoughts,
|
|
189
|
+
tool: msg.tokens.tool,
|
|
190
|
+
total: msg.tokens.total
|
|
191
|
+
} : undefined,
|
|
192
|
+
model: msg.model
|
|
193
|
+
}));
|
|
194
|
+
}
|
|
195
|
+
async extractToolCalls(descriptor) {
|
|
196
|
+
const filePath = descriptor.filePaths[0];
|
|
197
|
+
const session = await readJSON(filePath);
|
|
198
|
+
const toolCalls = [];
|
|
199
|
+
for (const message of session.messages) {
|
|
200
|
+
if (message.toolCalls) {
|
|
201
|
+
for (const tc of message.toolCalls) {
|
|
202
|
+
// Detect file modifications
|
|
203
|
+
const modifiedFiles = [];
|
|
204
|
+
if (['write_file', 'edit_file', 'create_file'].includes(tc.name)) {
|
|
205
|
+
const filePath = tc.args.file_path || tc.args.path;
|
|
206
|
+
if (filePath && typeof filePath === 'string') {
|
|
207
|
+
modifiedFiles.push(filePath);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
toolCalls.push({
|
|
211
|
+
toolCallId: tc.id,
|
|
212
|
+
messageId: message.id,
|
|
213
|
+
sessionId: session.sessionId,
|
|
214
|
+
timestamp: new Date(tc.timestamp),
|
|
215
|
+
toolName: tc.name,
|
|
216
|
+
toolArgs: tc.args,
|
|
217
|
+
status: tc.status,
|
|
218
|
+
result: tc.result,
|
|
219
|
+
modifiedFiles: modifiedFiles.length > 0 ? modifiedFiles : undefined
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return toolCalls;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Calculate metrics for write_file operations
|
|
228
|
+
*/
|
|
229
|
+
calculateWriteFileMetrics(toolCall) {
|
|
230
|
+
const content = toolCall.args.content || '';
|
|
231
|
+
const lines = countLines(content);
|
|
232
|
+
const bytes = calculateByteSize(content);
|
|
233
|
+
// Check if file was newly created (from result message)
|
|
234
|
+
const resultOutput = toolCall.result?.[0]?.functionResponse?.response?.output || '';
|
|
235
|
+
const wasNewFile = resultOutput.includes('Successfully created and wrote to new file');
|
|
236
|
+
return {
|
|
237
|
+
linesAdded: lines,
|
|
238
|
+
linesRemoved: wasNewFile ? 0 : 0, // Can't determine removed lines without file system access
|
|
239
|
+
linesModified: 0,
|
|
240
|
+
sizeBytes: bytes,
|
|
241
|
+
wasNewFile
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Calculate metrics for replace operations
|
|
246
|
+
*/
|
|
247
|
+
calculateReplaceMetrics(toolCall) {
|
|
248
|
+
const oldString = toolCall.args.old_string || '';
|
|
249
|
+
const newString = toolCall.args.new_string || '';
|
|
250
|
+
const oldLines = countLines(oldString);
|
|
251
|
+
const newLines = countLines(newString);
|
|
252
|
+
return {
|
|
253
|
+
linesAdded: Math.max(0, newLines - oldLines),
|
|
254
|
+
linesRemoved: Math.max(0, oldLines - newLines),
|
|
255
|
+
linesModified: Math.min(oldLines, newLines),
|
|
256
|
+
wasNewFile: false // replace only works on existing files
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
async extractFileModifications(descriptor) {
|
|
260
|
+
const filePath = descriptor.filePaths[0];
|
|
261
|
+
const session = await readJSON(filePath);
|
|
262
|
+
const modifications = [];
|
|
263
|
+
for (const message of session.messages) {
|
|
264
|
+
if (message.toolCalls) {
|
|
265
|
+
for (const tc of message.toolCalls) {
|
|
266
|
+
// Check if this is a file modification tool
|
|
267
|
+
if (['write_file', 'replace', 'smart_edit', 'edit_file', 'create_file'].includes(tc.name)) {
|
|
268
|
+
const targetFilePath = tc.args.file_path || tc.args.path;
|
|
269
|
+
if (!targetFilePath)
|
|
270
|
+
continue;
|
|
271
|
+
// Calculate metrics based on tool type
|
|
272
|
+
let metrics;
|
|
273
|
+
if (tc.name === 'write_file' || tc.name === 'create_file') {
|
|
274
|
+
metrics = this.calculateWriteFileMetrics(tc);
|
|
275
|
+
}
|
|
276
|
+
else if (tc.name === 'replace' || tc.name === 'smart_edit' || tc.name === 'edit_file') {
|
|
277
|
+
metrics = {
|
|
278
|
+
...this.calculateReplaceMetrics(tc),
|
|
279
|
+
sizeBytes: tc.args.new_string ? calculateByteSize(tc.args.new_string) : undefined
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
continue; // Skip unknown tools
|
|
284
|
+
}
|
|
285
|
+
// Determine operation type
|
|
286
|
+
let operation = 'update';
|
|
287
|
+
if (metrics.wasNewFile) {
|
|
288
|
+
operation = 'create';
|
|
289
|
+
}
|
|
290
|
+
else if (tc.name.includes('delete')) {
|
|
291
|
+
operation = 'delete';
|
|
292
|
+
}
|
|
293
|
+
// Detect language and format
|
|
294
|
+
const fileExtension = extname(targetFilePath);
|
|
295
|
+
const language = detectLanguage(targetFilePath);
|
|
296
|
+
const format = detectFormat(targetFilePath);
|
|
297
|
+
modifications.push({
|
|
298
|
+
sessionId: session.sessionId,
|
|
299
|
+
toolCallId: tc.id,
|
|
300
|
+
timestamp: new Date(tc.timestamp),
|
|
301
|
+
filePath: targetFilePath,
|
|
302
|
+
operation,
|
|
303
|
+
linesAdded: metrics.linesAdded,
|
|
304
|
+
linesRemoved: metrics.linesRemoved,
|
|
305
|
+
linesModified: metrics.linesModified,
|
|
306
|
+
sizeBytes: metrics.sizeBytes,
|
|
307
|
+
toolName: tc.name,
|
|
308
|
+
wasNewFile: metrics.wasNewFile,
|
|
309
|
+
fileExtension,
|
|
310
|
+
language,
|
|
311
|
+
format
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return modifications;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=gemini.adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.adapter.js","sourceRoot":"","sources":["../../../../src/analytics/aggregation/adapters/gemini.adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EACL,oBAAoB,EAEpB,WAAW,EACX,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,cAAc,EACd,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,kBAAkB,CAAC;AAgD1B;;GAEG;AACH,MAAM,OAAO,sBAAuB,SAAQ,oBAAoB;IAC9D,YAAY,QAAyB;QACnC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAA6B;QAC9C,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAEpC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,WAAW,GAAwB,EAAE,CAAC;QAE5C,oCAAoC;QACpC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACrD,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAEnE,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;gBACrC,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE;oBAAE,SAAS;gBAExC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBACxD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;oBAAE,SAAS;gBAEpC,yBAAyB;gBACzB,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;gBAErE,8BAA8B;gBAC9B,IAAI,aAAa,GAAG,YAAY,CAAC;gBACjC,IAAI,OAAO,EAAE,QAAQ,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;oBACzC,aAAa,GAAG,MAAM,iBAAiB,CAAC,YAAY,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;gBAC1F,CAAC;gBAED,qBAAqB;gBACrB,KAAK,MAAM,QAAQ,IAAI,aAAa,EAAE,CAAC;oBACrC,IAAI,CAAC;wBACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;wBACzC,WAAW,CAAC,IAAI,CAAC;4BACf,SAAS,EAAE,OAAO,CAAC,SAAS;4BAC5B,KAAK,EAAE,IAAI,CAAC,SAAS;4BACrB,SAAS,EAAE,CAAC,QAAQ,CAAC;4BACrB,QAAQ,EAAE;gCACR,WAAW,EAAE,OAAO,CAAC,WAAW;gCAChC,SAAS,EAAE,OAAO,CAAC,SAAS;gCAC5B,WAAW,EAAE,OAAO,CAAC,WAAW;6BACjC;yBACF,CAAC,CAAC;oBACL,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,QAAQ,KAAK,KAAK,EAAE,CAAC,CAAC;oBACrE,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,mCAAmC,KAAK,EAAE,CAAC,CAAC;QAC5D,CAAC;QAED,0CAA0C;QAC1C,OAAO,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,UAA6B;QAChD,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,OAAO,GAAsB,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE5D,yBAAyB;QACzB,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;QACrE,MAAM,iBAAiB,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;QAE5E,gEAAgE;QAChE,IAAI,cAAc,GAAG,CAAC,CAAC;QACvB,IAAI,mBAAmB,GAAG,CAAC,CAAC;QAC5B,IAAI,eAAe,GAAG,CAAC,CAAC;QACxB,MAAM,SAAS,GAA2B,EAAE,CAAC;QAC7C,MAAM,UAAU,GAAyD,EAAE,CAAC;QAE5E,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACvC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;gBACtB,cAAc,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC;gBAC3C,mBAAmB,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;gBACtF,eAAe,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;gBAElF,8BAA8B;gBAC9B,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;oBACnC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;oBAEnD,iCAAiC;oBACjC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;wBACzB,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;oBACnD,CAAC;oBACD,IAAI,EAAE,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;wBAC5B,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;oBAChC,CAAC;yBAAM,IAAI,EAAE,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;wBACnC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;oBAChC,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,+CAA+C;QAC/C,MAAM,UAAU,GAA2B,EAAE,CAAC;QAC9C,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACvC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBAClB,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;QAED,mEAAmE;QACnE,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAAC;QAE1E,qCAAqC;QACrC,IAAI,gBAAgB,GAAG,CAAC,CAAC;QACzB,IAAI,iBAAiB,GAAG,CAAC,CAAC;QAC1B,IAAI,iBAAiB,GAAG,CAAC,CAAC;QAC1B,IAAI,mBAAmB,GAAG,CAAC,CAAC;QAC5B,IAAI,eAAe,GAAG,CAAC,CAAC;QACxB,IAAI,WAAW,GAAG,CAAC,CAAC;QAEpB,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACvC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;gBAC9C,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;gBAChD,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;gBAChD,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;gBACpD,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC;gBAC5C,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;QAED,qBAAqB;QACrB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;QAE3D,mBAAmB;QACnB,MAAM,SAAS,GAAG,eAAe,GAAG,CAAC,CAAC;QAEtC,+CAA+C;QAC/C,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,IAAI,gBAAgB,CAAC;QAE9E,iDAAiD;QACjD,MAAM,SAAS,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAC;QAExD,oDAAoD;QACpD,wDAAwD;QACxD,MAAM,WAAW,GAAG,UAAU,CAAC,QAAQ,CAAC,WAAqB;YACzC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAEnG,OAAO;YACL,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,KAAK,EAAE,QAAQ;YACf,YAAY,EAAE,OAAO;YACrB,SAAS;YACT,OAAO;YACP,UAAU;YACV,WAAW;YACX,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,KAAK;YACL,QAAQ,EAAE,QAAQ;YAClB,gBAAgB,EAAE,YAAY,CAAC,MAAM;YACrC,qBAAqB,EAAE,iBAAiB,CAAC,MAAM;YAC/C,aAAa,EAAE,cAAc;YAC7B,mBAAmB;YACnB,eAAe;YACf,iBAAiB,EAAE,iBAAiB,CAAC,MAAM;YAC3C,SAAS;YACT,UAAU;YACV,UAAU;YACV,MAAM,EAAE;gBACN,KAAK,EAAE,gBAAgB;gBACvB,MAAM,EAAE,iBAAiB;gBACzB,SAAS,EAAE,iBAAiB;gBAC5B,aAAa,EAAE,CAAC,EAAE,qDAAqD;gBACvE,QAAQ,EAAE,mBAAmB;gBAC7B,IAAI,EAAE,eAAe;gBACrB,KAAK,EAAE,WAAW;aACnB;YACD,SAAS;YACT,SAAS;SACV,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,UAA6B;QACjD,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,OAAO,GAAsB,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE5D,OAAO,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAClC,SAAS,EAAE,GAAG,CAAC,EAAE;YACjB,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;YAClC,IAAI,EAAE,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW;YAChD,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;gBACnB,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK;gBACvB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM;gBACzB,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM;gBAC5B,aAAa,EAAE,CAAC;gBAChB,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ;gBAC7B,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI;gBACrB,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK;aACxB,CAAC,CAAC,CAAC,SAAS;YACb,KAAK,EAAE,GAAG,CAAC,KAAK;SACjB,CAAC,CAAC,CAAC;IACN,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,UAA6B;QAClD,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,OAAO,GAAsB,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE5D,MAAM,SAAS,GAAsB,EAAE,CAAC;QAExC,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACvC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;gBACtB,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;oBACnC,4BAA4B;oBAC5B,MAAM,aAAa,GAAa,EAAE,CAAC;oBACnC,IAAI,CAAC,YAAY,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;wBACjE,MAAM,QAAQ,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;wBACnD,IAAI,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;4BAC7C,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;wBAC/B,CAAC;oBACH,CAAC;oBAED,SAAS,CAAC,IAAI,CAAC;wBACb,UAAU,EAAE,EAAE,CAAC,EAAE;wBACjB,SAAS,EAAE,OAAO,CAAC,EAAE;wBACrB,SAAS,EAAE,OAAO,CAAC,SAAS;wBAC5B,SAAS,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC;wBACjC,QAAQ,EAAE,EAAE,CAAC,IAAI;wBACjB,QAAQ,EAAE,EAAE,CAAC,IAAI;wBACjB,MAAM,EAAE,EAAE,CAAC,MAAM;wBACjB,MAAM,EAAE,EAAE,CAAC,MAAM;wBACjB,aAAa,EAAE,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS;qBACpE,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;OAEG;IACK,yBAAyB,CAC/B,QAAwB;QAExB,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAiB,IAAI,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAClC,MAAM,KAAK,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAEzC,wDAAwD;QACxD,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,IAAI,EAAE,CAAC;QACpF,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,4CAA4C,CAAC,CAAC;QAEvF,OAAO;YACL,UAAU,EAAE,KAAK;YACjB,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,2DAA2D;YAC7F,aAAa,EAAE,CAAC;YAChB,SAAS,EAAE,KAAK;YAChB,UAAU;SACX,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,uBAAuB,CAC7B,QAAwB;QAExB,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,UAAoB,IAAI,EAAE,CAAC;QAC3D,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,UAAoB,IAAI,EAAE,CAAC;QAE3D,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;QAEvC,OAAO;YACL,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;YAC5C,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;YAC9C,aAAa,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC;YAC3C,UAAU,EAAE,KAAK,CAAC,uCAAuC;SAC1D,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,wBAAwB,CAAC,UAA6B;QAC1D,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,OAAO,GAAsB,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC5D,MAAM,aAAa,GAA8B,EAAE,CAAC;QAEpD,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACvC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;gBACtB,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;oBACnC,4CAA4C;oBAC5C,IAAI,CAAC,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC1F,MAAM,cAAc,GAAG,EAAE,CAAC,IAAI,CAAC,SAAmB,IAAI,EAAE,CAAC,IAAI,CAAC,IAAc,CAAC;wBAC7E,IAAI,CAAC,cAAc;4BAAE,SAAS;wBAE9B,uCAAuC;wBACvC,IAAI,OAAoH,CAAC;wBAEzH,IAAI,EAAE,CAAC,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;4BAC1D,OAAO,GAAG,IAAI,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC;wBAC/C,CAAC;6BAAM,IAAI,EAAE,CAAC,IAAI,KAAK,SAAS,IAAI,EAAE,CAAC,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;4BACxF,OAAO,GAAG;gCACR,GAAG,IAAI,CAAC,uBAAuB,CAAC,EAAE,CAAC;gCACnC,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,iBAAiB,CAAC,EAAE,CAAC,IAAI,CAAC,UAAoB,CAAC,CAAC,CAAC,CAAC,SAAS;6BAC5F,CAAC;wBACJ,CAAC;6BAAM,CAAC;4BACN,SAAS,CAAC,qBAAqB;wBACjC,CAAC;wBAED,2BAA2B;wBAC3B,IAAI,SAAS,GAAmC,QAAQ,CAAC;wBACzD,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;4BACvB,SAAS,GAAG,QAAQ,CAAC;wBACvB,CAAC;6BAAM,IAAI,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;4BACtC,SAAS,GAAG,QAAQ,CAAC;wBACvB,CAAC;wBAED,6BAA6B;wBAC7B,MAAM,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;wBAC9C,MAAM,QAAQ,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;wBAChD,MAAM,MAAM,GAAG,YAAY,CAAC,cAAc,CAAC,CAAC;wBAE5C,aAAa,CAAC,IAAI,CAAC;4BACjB,SAAS,EAAE,OAAO,CAAC,SAAS;4BAC5B,UAAU,EAAE,EAAE,CAAC,EAAE;4BACjB,SAAS,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC;4BACjC,QAAQ,EAAE,cAAc;4BACxB,SAAS;4BACT,UAAU,EAAE,OAAO,CAAC,UAAU;4BAC9B,YAAY,EAAE,OAAO,CAAC,YAAY;4BAClC,aAAa,EAAE,OAAO,CAAC,aAAa;4BACpC,SAAS,EAAE,OAAO,CAAC,SAAS;4BAC5B,QAAQ,EAAE,EAAE,CAAC,IAAI;4BACjB,UAAU,EAAE,OAAO,CAAC,UAAU;4BAC9B,aAAa;4BACb,QAAQ;4BACR,MAAM;yBACP,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,aAAa,CAAC;IACvB,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/analytics/aggregation/adapters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/analytics/aggregation/adapters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeMie Analytics Aggregator
|
|
3
|
+
*
|
|
4
|
+
* Main service for aggregating analytics data from multiple AI agents.
|
|
5
|
+
* Uses AgentRegistry to automatically discover all registered analytics adapters.
|
|
6
|
+
*/
|
|
7
|
+
import { AggregationOptions, CodemieSession, SessionDetails, AnalyticsReport } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Main aggregator service
|
|
10
|
+
*/
|
|
11
|
+
export declare class CodemieAnalyticsAggregator {
|
|
12
|
+
/**
|
|
13
|
+
* Aggregate sessions from all agents
|
|
14
|
+
*/
|
|
15
|
+
aggregateSessions(options?: AggregationOptions): Promise<CodemieSession[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Get detailed information for a specific session
|
|
18
|
+
*/
|
|
19
|
+
getSessionDetails(sessionId: string, agentName: string): Promise<SessionDetails>;
|
|
20
|
+
/**
|
|
21
|
+
* Generate analytics report with statistics
|
|
22
|
+
*/
|
|
23
|
+
generateReport(options?: AggregationOptions): Promise<AnalyticsReport>;
|
|
24
|
+
/**
|
|
25
|
+
* Calculate summary statistics
|
|
26
|
+
*/
|
|
27
|
+
private calculateSummary;
|
|
28
|
+
/**
|
|
29
|
+
* Calculate success rate (sessions without errors)
|
|
30
|
+
*/
|
|
31
|
+
private calculateSuccessRate;
|
|
32
|
+
/**
|
|
33
|
+
* Group sessions by agent
|
|
34
|
+
*/
|
|
35
|
+
private groupByAgent;
|
|
36
|
+
/**
|
|
37
|
+
* Group sessions by model
|
|
38
|
+
*/
|
|
39
|
+
private groupByModel;
|
|
40
|
+
/**
|
|
41
|
+
* Group sessions by project
|
|
42
|
+
*/
|
|
43
|
+
private groupByProject;
|
|
44
|
+
/**
|
|
45
|
+
* Group sessions by day
|
|
46
|
+
*/
|
|
47
|
+
private groupByDay;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=aggregator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregator.d.ts","sourceRoot":"","sources":["../../../src/analytics/aggregation/aggregator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,eAAe,EAMhB,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,qBAAa,0BAA0B;IACrC;;OAEG;IACG,iBAAiB,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAiDpF;;OAEG;IACG,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA+BtF;;OAEG;IACG,cAAc,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,eAAe,CAAC;IAehF;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAwBxB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAM5B;;OAEG;IACH,OAAO,CAAC,YAAY;IAwCpB;;OAEG;IACH,OAAO,CAAC,YAAY;IA0BpB;;OAEG;IACH,OAAO,CAAC,cAAc;IAsBtB;;OAEG;IACH,OAAO,CAAC,UAAU;CAsBnB"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeMie Analytics Aggregator
|
|
3
|
+
*
|
|
4
|
+
* Main service for aggregating analytics data from multiple AI agents.
|
|
5
|
+
* Uses AgentRegistry to automatically discover all registered analytics adapters.
|
|
6
|
+
*/
|
|
7
|
+
import { AgentRegistry } from '../../agents/registry.js';
|
|
8
|
+
/**
|
|
9
|
+
* Main aggregator service
|
|
10
|
+
*/
|
|
11
|
+
export class CodemieAnalyticsAggregator {
|
|
12
|
+
/**
|
|
13
|
+
* Aggregate sessions from all agents
|
|
14
|
+
*/
|
|
15
|
+
async aggregateSessions(options = {}) {
|
|
16
|
+
const sessions = [];
|
|
17
|
+
// Get all analytics adapters from registry (automatically registered with plugins)
|
|
18
|
+
const adapters = AgentRegistry.getAllAnalyticsAdapters();
|
|
19
|
+
// Filter by agent if specified
|
|
20
|
+
const filteredAdapters = options.agent
|
|
21
|
+
? adapters.filter(a => a.agentName === options.agent)
|
|
22
|
+
: adapters;
|
|
23
|
+
// Query all adapters in parallel
|
|
24
|
+
const promises = filteredAdapters.map(async (adapter) => {
|
|
25
|
+
try {
|
|
26
|
+
// Check if source is valid
|
|
27
|
+
const isValid = await adapter.validateSource();
|
|
28
|
+
if (!isValid) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// Find sessions matching criteria
|
|
32
|
+
const descriptors = await adapter.findSessions({
|
|
33
|
+
projectPath: options.projectPath,
|
|
34
|
+
dateFrom: options.dateFrom,
|
|
35
|
+
dateTo: options.dateTo,
|
|
36
|
+
limit: options.limit,
|
|
37
|
+
offset: options.offset
|
|
38
|
+
});
|
|
39
|
+
// Extract session details
|
|
40
|
+
for (const descriptor of descriptors) {
|
|
41
|
+
try {
|
|
42
|
+
const session = await adapter.extractSession(descriptor);
|
|
43
|
+
sessions.push(session);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.error(`Error extracting session ${descriptor.sessionId}: ${error}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
console.error(`Error aggregating ${adapter.displayName} (${adapter.agentName}): ${error}`);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
await Promise.all(promises);
|
|
55
|
+
// Sort by startTime
|
|
56
|
+
return sessions.sort((a, b) => a.startTime.getTime() - b.startTime.getTime());
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get detailed information for a specific session
|
|
60
|
+
*/
|
|
61
|
+
async getSessionDetails(sessionId, agentName) {
|
|
62
|
+
// Get adapter from registry
|
|
63
|
+
const adapter = AgentRegistry.getAnalyticsAdapter(agentName);
|
|
64
|
+
if (!adapter) {
|
|
65
|
+
throw new Error(`Unknown agent or no analytics adapter: ${agentName}`);
|
|
66
|
+
}
|
|
67
|
+
// Find session descriptor
|
|
68
|
+
const descriptors = await adapter.findSessions();
|
|
69
|
+
const descriptor = descriptors.find(d => d.sessionId === sessionId);
|
|
70
|
+
if (!descriptor) {
|
|
71
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
72
|
+
}
|
|
73
|
+
// Extract all details in parallel
|
|
74
|
+
const [session, messages, toolCalls, fileModifications] = await Promise.all([
|
|
75
|
+
adapter.extractSession(descriptor),
|
|
76
|
+
adapter.extractMessages(descriptor),
|
|
77
|
+
adapter.extractToolCalls(descriptor),
|
|
78
|
+
adapter.extractFileModifications(descriptor)
|
|
79
|
+
]);
|
|
80
|
+
return {
|
|
81
|
+
session,
|
|
82
|
+
messages,
|
|
83
|
+
toolCalls,
|
|
84
|
+
fileModifications
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Generate analytics report with statistics
|
|
89
|
+
*/
|
|
90
|
+
async generateReport(options = {}) {
|
|
91
|
+
const sessions = await this.aggregateSessions(options);
|
|
92
|
+
return {
|
|
93
|
+
summary: this.calculateSummary(sessions),
|
|
94
|
+
sessions,
|
|
95
|
+
breakdown: {
|
|
96
|
+
byAgent: this.groupByAgent(sessions),
|
|
97
|
+
byModel: this.groupByModel(sessions),
|
|
98
|
+
byProject: this.groupByProject(sessions),
|
|
99
|
+
byDay: this.groupByDay(sessions)
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Calculate summary statistics
|
|
105
|
+
*/
|
|
106
|
+
calculateSummary(sessions) {
|
|
107
|
+
const totalMessages = sessions.reduce((sum, s) => sum + s.userMessageCount + s.assistantMessageCount, 0);
|
|
108
|
+
const totalTokens = sessions.reduce((sum, s) => sum + s.tokens.total, 0);
|
|
109
|
+
const totalToolCalls = sessions.reduce((sum, s) => sum + s.toolCallCount, 0);
|
|
110
|
+
const totalFileModifications = sessions.reduce((sum, s) => sum + s.fileModifications, 0);
|
|
111
|
+
const durations = sessions.map(s => s.durationMs || 0).filter(d => d > 0);
|
|
112
|
+
const averageSessionDuration = durations.length > 0
|
|
113
|
+
? durations.reduce((sum, d) => sum + d, 0) / durations.length
|
|
114
|
+
: 0;
|
|
115
|
+
const successRate = this.calculateSuccessRate(sessions);
|
|
116
|
+
return {
|
|
117
|
+
totalSessions: sessions.length,
|
|
118
|
+
totalMessages,
|
|
119
|
+
totalTokens,
|
|
120
|
+
totalToolCalls,
|
|
121
|
+
totalFileModifications,
|
|
122
|
+
averageSessionDuration,
|
|
123
|
+
successRate
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Calculate success rate (sessions without errors)
|
|
128
|
+
*/
|
|
129
|
+
calculateSuccessRate(sessions) {
|
|
130
|
+
if (sessions.length === 0)
|
|
131
|
+
return 0;
|
|
132
|
+
const successfulSessions = sessions.filter(s => !s.hadErrors).length;
|
|
133
|
+
return successfulSessions / sessions.length;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Group sessions by agent
|
|
137
|
+
*/
|
|
138
|
+
groupByAgent(sessions) {
|
|
139
|
+
const grouped = {};
|
|
140
|
+
for (const session of sessions) {
|
|
141
|
+
if (!grouped[session.agent]) {
|
|
142
|
+
grouped[session.agent] = {
|
|
143
|
+
sessions: 0,
|
|
144
|
+
messages: 0,
|
|
145
|
+
tokens: 0,
|
|
146
|
+
toolCalls: 0,
|
|
147
|
+
fileModifications: 0,
|
|
148
|
+
averageDuration: 0,
|
|
149
|
+
successRate: 0
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
const stats = grouped[session.agent];
|
|
153
|
+
stats.sessions++;
|
|
154
|
+
stats.messages += session.userMessageCount + session.assistantMessageCount;
|
|
155
|
+
stats.tokens += session.tokens.total;
|
|
156
|
+
stats.toolCalls += session.toolCallCount;
|
|
157
|
+
stats.fileModifications += session.fileModifications;
|
|
158
|
+
}
|
|
159
|
+
// Calculate averages
|
|
160
|
+
for (const agent in grouped) {
|
|
161
|
+
const stats = grouped[agent];
|
|
162
|
+
const agentSessions = sessions.filter(s => s.agent === agent);
|
|
163
|
+
const durations = agentSessions.map(s => s.durationMs || 0).filter(d => d > 0);
|
|
164
|
+
stats.averageDuration = durations.length > 0
|
|
165
|
+
? durations.reduce((sum, d) => sum + d, 0) / durations.length
|
|
166
|
+
: 0;
|
|
167
|
+
stats.successRate = this.calculateSuccessRate(agentSessions);
|
|
168
|
+
}
|
|
169
|
+
return grouped;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Group sessions by model
|
|
173
|
+
*/
|
|
174
|
+
groupByModel(sessions) {
|
|
175
|
+
const grouped = {};
|
|
176
|
+
for (const session of sessions) {
|
|
177
|
+
if (!grouped[session.model]) {
|
|
178
|
+
grouped[session.model] = {
|
|
179
|
+
sessions: 0,
|
|
180
|
+
tokens: 0,
|
|
181
|
+
averageTokensPerSession: 0
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
const stats = grouped[session.model];
|
|
185
|
+
stats.sessions++;
|
|
186
|
+
stats.tokens += session.tokens.total;
|
|
187
|
+
}
|
|
188
|
+
// Calculate averages
|
|
189
|
+
for (const model in grouped) {
|
|
190
|
+
const stats = grouped[model];
|
|
191
|
+
stats.averageTokensPerSession = stats.tokens / stats.sessions;
|
|
192
|
+
}
|
|
193
|
+
return grouped;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Group sessions by project
|
|
197
|
+
*/
|
|
198
|
+
groupByProject(sessions) {
|
|
199
|
+
const grouped = {};
|
|
200
|
+
for (const session of sessions) {
|
|
201
|
+
const project = session.projectPath || 'other';
|
|
202
|
+
if (!grouped[project]) {
|
|
203
|
+
grouped[project] = {
|
|
204
|
+
sessions: 0,
|
|
205
|
+
messages: 0,
|
|
206
|
+
fileModifications: 0
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
const stats = grouped[project];
|
|
210
|
+
stats.sessions++;
|
|
211
|
+
stats.messages += session.userMessageCount + session.assistantMessageCount;
|
|
212
|
+
stats.fileModifications += session.fileModifications;
|
|
213
|
+
}
|
|
214
|
+
return grouped;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Group sessions by day
|
|
218
|
+
*/
|
|
219
|
+
groupByDay(sessions) {
|
|
220
|
+
const grouped = {};
|
|
221
|
+
for (const session of sessions) {
|
|
222
|
+
const date = session.startTime.toISOString().split('T')[0];
|
|
223
|
+
if (!grouped[date]) {
|
|
224
|
+
grouped[date] = {
|
|
225
|
+
date,
|
|
226
|
+
sessions: 0,
|
|
227
|
+
messages: 0,
|
|
228
|
+
tokens: 0
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const stats = grouped[date];
|
|
232
|
+
stats.sessions++;
|
|
233
|
+
stats.messages += session.userMessageCount + session.assistantMessageCount;
|
|
234
|
+
stats.tokens += session.tokens.total;
|
|
235
|
+
}
|
|
236
|
+
return grouped;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=aggregator.js.map
|