coding-tool-x 3.6.13 → 3.7.1

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 (88) hide show
  1. package/README.md +45 -33
  2. package/dist/web/assets/{Analytics-CnA75GxO.js → Analytics-Dpje9L84.js} +1 -1
  3. package/dist/web/assets/{ConfigTemplates-D8XEscQY.js → ConfigTemplates-Cz6kasek.js} +1 -1
  4. package/dist/web/assets/Home-BwTaYu3q.js +1 -0
  5. package/dist/web/assets/Home-Jom_ZcdY.css +1 -0
  6. package/dist/web/assets/{PluginManager-BzKZ8TYu.js → PluginManager-DsN-xNXx.js} +1 -1
  7. package/dist/web/assets/ProjectList-4BCObimU.js +1 -0
  8. package/dist/web/assets/{ProjectList-DL4JK6ci.css → ProjectList-D3a0oRum.css} +1 -1
  9. package/dist/web/assets/SessionList-D4c8FRzq.js +1 -0
  10. package/dist/web/assets/{SkillManager-fxOvFTYD.js → SkillManager-C-KYbXB5.js} +1 -1
  11. package/dist/web/assets/{WorkspaceManager-Ch2mM8jm.js → WorkspaceManager-B-BlPJHX.js} +1 -1
  12. package/dist/web/assets/{icons-QFXzEgqM.js → icons-Dop5j7Bf.js} +1 -1
  13. package/dist/web/assets/index-Btfvh0GG.js +2 -0
  14. package/dist/web/assets/index-CLNa6DhH.css +1 -0
  15. package/dist/web/assets/{naive-ui-kcWDeJwl.js → naive-ui-CVyvdmg1.js} +1 -1
  16. package/dist/web/index.html +4 -4
  17. package/package.json +3 -1
  18. package/src/commands/channels.js +85 -24
  19. package/src/commands/daemon.js +7 -4
  20. package/src/commands/doctor.js +17 -8
  21. package/src/commands/logs.js +46 -6
  22. package/src/commands/port-config.js +83 -75
  23. package/src/commands/proxy-control.js +59 -26
  24. package/src/commands/stats.js +37 -19
  25. package/src/commands/switch.js +5 -1
  26. package/src/commands/toggle-proxy.js +131 -53
  27. package/src/commands/ui.js +3 -4
  28. package/src/commands/workspace.js +3 -35
  29. package/src/config/default.js +19 -2
  30. package/src/config/loader.js +5 -76
  31. package/src/config/paths.js +96 -11
  32. package/src/index.js +10 -16
  33. package/src/server/api/commands.js +1 -1
  34. package/src/server/api/config-export.js +4 -2
  35. package/src/server/api/config-registry.js +40 -34
  36. package/src/server/api/config.js +5 -1
  37. package/src/server/api/dashboard.js +22 -6
  38. package/src/server/api/mcp.js +5 -3
  39. package/src/server/api/omp-channels.js +349 -0
  40. package/src/server/api/omp-config.js +164 -0
  41. package/src/server/api/omp-projects.js +76 -0
  42. package/src/server/api/omp-proxy.js +154 -0
  43. package/src/server/api/omp-sessions.js +334 -0
  44. package/src/server/api/omp-statistics.js +40 -0
  45. package/src/server/api/plugins.js +1 -1
  46. package/src/server/api/prompts.js +3 -2
  47. package/src/server/api/settings.js +2 -0
  48. package/src/server/api/skills.js +1 -1
  49. package/src/server/api/workspaces.js +3 -41
  50. package/src/server/index.js +41 -0
  51. package/src/server/omp-proxy-server.js +66 -0
  52. package/src/server/services/agents-service.js +2 -1
  53. package/src/server/services/base/proxy-utils.js +1 -0
  54. package/src/server/services/channel-balance.js +151 -1
  55. package/src/server/services/channel-scheduler.js +7 -1
  56. package/src/server/services/commands-service.js +11 -2
  57. package/src/server/services/config-export-service.js +296 -39
  58. package/src/server/services/config-registry-service.js +20 -18
  59. package/src/server/services/config-sync-manager.js +115 -6
  60. package/src/server/services/config-sync-service.js +4 -2
  61. package/src/server/services/config-templates-service.js +183 -45
  62. package/src/server/services/mcp-service.js +217 -33
  63. package/src/server/services/notification-hooks.js +138 -6
  64. package/src/server/services/omp-auth-providers.js +294 -0
  65. package/src/server/services/omp-channels.js +94 -0
  66. package/src/server/services/omp-config.js +269 -0
  67. package/src/server/services/omp-sessions.js +490 -0
  68. package/src/server/services/omp-settings-manager.js +975 -0
  69. package/src/server/services/omp-statistics-service.js +317 -0
  70. package/src/server/services/plugins-service.js +673 -11
  71. package/src/server/services/prompts-service.js +112 -7
  72. package/src/server/services/proxy-log-helper.js +1 -0
  73. package/src/server/services/proxy-runtime.js +5 -1
  74. package/src/server/services/sessions.js +19 -35
  75. package/src/server/services/skill-service.js +13 -3
  76. package/src/server/services/speed-test.js +34 -28
  77. package/src/server/services/ui-config.js +50 -12
  78. package/src/server/services/workspace-service.js +117 -225
  79. package/src/server/websocket-server.js +7 -1
  80. package/src/shared/platforms.js +201 -0
  81. package/src/utils/session.js +4 -10
  82. package/dist/web/assets/Home-BiaKZMah.js +0 -1
  83. package/dist/web/assets/Home-CIua-b-o.css +0 -1
  84. package/dist/web/assets/ProjectList-BPfG_92X.js +0 -1
  85. package/dist/web/assets/SessionList-BIVtw00v.js +0 -1
  86. package/dist/web/assets/index-BpBFF3b2.js +0 -2
  87. package/dist/web/assets/index-Dsh4Q5Cg.css +0 -1
  88. package/src/utils/cli-flags.js +0 -7
@@ -0,0 +1,317 @@
1
+ const {
2
+ recordRequest: recordSharedRequest,
3
+ getStatistics: getSharedStatistics,
4
+ getDailyStatistics: getSharedDailyStatistics,
5
+ getTodayStatistics: getSharedTodayStatistics
6
+ } = require('./statistics-service');
7
+ const { normalizeUsageTokens, toNumber } = require('./proxy-log-helper');
8
+
9
+ const TOOL_TYPE = 'omp';
10
+
11
+ function initAggregateEntry(name = '') {
12
+ return {
13
+ name,
14
+ requests: 0,
15
+ tokens: {
16
+ input: 0,
17
+ output: 0,
18
+ reasoning: 0,
19
+ cached: 0,
20
+ total: 0
21
+ },
22
+ cost: 0,
23
+ firstUsed: null,
24
+ lastUsed: null
25
+ };
26
+ }
27
+
28
+ function toLegacyEntryShape(entry = {}, includeName = false) {
29
+ const normalized = normalizeUsageTokens(TOOL_TYPE, entry.tokens || {});
30
+ const result = {
31
+ requests: toNumber(entry.requests),
32
+ tokens: {
33
+ input: normalized.input,
34
+ output: normalized.output,
35
+ reasoning: normalized.reasoning,
36
+ cached: normalized.cached,
37
+ total: normalized.total
38
+ },
39
+ cost: toNumber(entry.cost)
40
+ };
41
+
42
+ if (includeName) {
43
+ result.name = entry.name || '';
44
+ if (entry.firstUsed) result.firstUsed = entry.firstUsed;
45
+ if (entry.lastUsed) result.lastUsed = entry.lastUsed;
46
+ }
47
+
48
+ return result;
49
+ }
50
+
51
+ function pickToolScope(sharedStats = {}) {
52
+ const byToolType = sharedStats.byToolType || {};
53
+ const toolScope = byToolType[TOOL_TYPE] || {};
54
+
55
+ const byChannel = toolScope.channels && typeof toolScope.channels === 'object'
56
+ ? toolScope.channels
57
+ : Object.fromEntries(
58
+ Object.entries(sharedStats.byChannel || {}).filter(([, value]) => value?.toolType === TOOL_TYPE)
59
+ );
60
+
61
+ const byModel = toolScope.models && typeof toolScope.models === 'object'
62
+ ? toolScope.models
63
+ : Object.fromEntries(
64
+ Object.entries(sharedStats.byModel || {}).filter(([, value]) => value?.toolType === TOOL_TYPE)
65
+ );
66
+
67
+ return { toolScope, byChannel, byModel };
68
+ }
69
+
70
+ function buildSummaryStatistics(sharedStats = {}) {
71
+ const { toolScope, byChannel, byModel } = pickToolScope(sharedStats);
72
+ const normalized = toLegacyEntryShape(toolScope);
73
+
74
+ return {
75
+ version: '1.0',
76
+ source: 'shared-stats',
77
+ lastUpdated: sharedStats.lastUpdated || new Date().toISOString(),
78
+ global: {
79
+ totalRequests: normalized.requests,
80
+ totalTokens: normalized.tokens.total,
81
+ totalCost: normalized.cost
82
+ },
83
+ byChannel: Object.fromEntries(
84
+ Object.entries(byChannel).map(([key, value]) => [key, toLegacyEntryShape(value, true)])
85
+ ),
86
+ byModel: Object.fromEntries(
87
+ Object.entries(byModel).map(([key, value]) => [key, toLegacyEntryShape(value)])
88
+ )
89
+ };
90
+ }
91
+
92
+ function buildDailyStatistics(sharedDaily = {}, fallbackDate) {
93
+ const { byToolType = {} } = sharedDaily;
94
+ const toolScope = byToolType[TOOL_TYPE] || {};
95
+ const normalized = toLegacyEntryShape(toolScope);
96
+ const byChannel = toolScope.channels || {};
97
+ const byModel = toolScope.models || {};
98
+
99
+ return {
100
+ date: sharedDaily.date || fallbackDate,
101
+ source: 'shared-stats',
102
+ summary: {
103
+ requests: normalized.requests,
104
+ tokens: normalized.tokens.total,
105
+ cost: normalized.cost
106
+ },
107
+ byChannel: Object.fromEntries(
108
+ Object.entries(byChannel).map(([key, value]) => [key, toLegacyEntryShape(value, true)])
109
+ ),
110
+ byModel: Object.fromEntries(
111
+ Object.entries(byModel).map(([key, value]) => [key, toLegacyEntryShape(value)])
112
+ )
113
+ };
114
+ }
115
+
116
+ function hasSummaryData(summary = {}) {
117
+ return Boolean(
118
+ summary.global?.totalRequests
119
+ || summary.global?.totalTokens
120
+ || summary.global?.totalCost
121
+ || Object.keys(summary.byChannel || {}).length
122
+ || Object.keys(summary.byModel || {}).length
123
+ );
124
+ }
125
+
126
+ function hasDailyData(daily = {}) {
127
+ return Boolean(
128
+ daily.summary?.requests
129
+ || daily.summary?.tokens
130
+ || daily.summary?.cost
131
+ || Object.keys(daily.byChannel || {}).length
132
+ || Object.keys(daily.byModel || {}).length
133
+ );
134
+ }
135
+
136
+ function getSessionTimestamp(session = {}) {
137
+ const value = session.timestamp || session.mtime || session.mtimeMs || null;
138
+ const date = value ? new Date(value) : null;
139
+ return date && !Number.isNaN(date.getTime()) ? date : null;
140
+ }
141
+
142
+ function getSessionDateKey(session = {}) {
143
+ const date = getSessionTimestamp(session);
144
+ return date ? date.toISOString().slice(0, 10) : null;
145
+ }
146
+
147
+ function getSessionUsage(session = {}) {
148
+ return normalizeUsageTokens(TOOL_TYPE, session.usage || session.tokens || {});
149
+ }
150
+
151
+ function addSessionUsage(entry, session) {
152
+ const tokens = getSessionUsage(session);
153
+ if (!tokens.total && !tokens.input && !tokens.output && !tokens.reasoning && !tokens.cached) {
154
+ return false;
155
+ }
156
+
157
+ entry.requests += 1;
158
+ entry.tokens.input += tokens.input;
159
+ entry.tokens.output += tokens.output;
160
+ entry.tokens.reasoning += tokens.reasoning;
161
+ entry.tokens.cached += tokens.cached;
162
+ entry.tokens.total += tokens.total;
163
+ entry.cost += toNumber(session.cost || session.usage?.cost || 0);
164
+
165
+ const timestamp = getSessionTimestamp(session);
166
+ if (timestamp) {
167
+ const iso = timestamp.toISOString();
168
+ if (!entry.firstUsed || iso < entry.firstUsed) entry.firstUsed = iso;
169
+ if (!entry.lastUsed || iso > entry.lastUsed) entry.lastUsed = iso;
170
+ }
171
+
172
+ return true;
173
+ }
174
+
175
+ function readSessionUsage() {
176
+ try {
177
+ const { getAllSessions } = require('./omp-sessions');
178
+ const sessions = getAllSessions();
179
+ return Array.isArray(sessions) ? sessions : [];
180
+ } catch {
181
+ return [];
182
+ }
183
+ }
184
+
185
+ function buildSessionDerivedStatistics(sessions = readSessionUsage()) {
186
+ const globalEntry = initAggregateEntry('OMP Sessions');
187
+ const byChannel = {};
188
+ const byModel = {};
189
+
190
+ sessions.forEach((session) => {
191
+ const tokens = getSessionUsage(session);
192
+ if (!tokens.total && !tokens.input && !tokens.output && !tokens.reasoning && !tokens.cached) {
193
+ return;
194
+ }
195
+
196
+ addSessionUsage(globalEntry, session);
197
+
198
+ const channelKey = session.provider || 'omp-session';
199
+ if (!byChannel[channelKey]) {
200
+ byChannel[channelKey] = initAggregateEntry(session.provider || 'OMP Session');
201
+ }
202
+ addSessionUsage(byChannel[channelKey], session);
203
+
204
+ const modelKey = session.model || 'unknown';
205
+ if (!byModel[modelKey]) {
206
+ byModel[modelKey] = initAggregateEntry(modelKey);
207
+ }
208
+ addSessionUsage(byModel[modelKey], session);
209
+ });
210
+
211
+ return {
212
+ version: '1.0',
213
+ source: globalEntry.requests > 0 ? 'sessions' : 'empty',
214
+ lastUpdated: globalEntry.lastUsed || new Date().toISOString(),
215
+ global: {
216
+ totalRequests: globalEntry.requests,
217
+ totalTokens: globalEntry.tokens.total,
218
+ totalCost: globalEntry.cost
219
+ },
220
+ byChannel: Object.fromEntries(
221
+ Object.entries(byChannel).map(([key, value]) => [key, toLegacyEntryShape(value, true)])
222
+ ),
223
+ byModel: Object.fromEntries(
224
+ Object.entries(byModel).map(([key, value]) => [key, toLegacyEntryShape(value)])
225
+ )
226
+ };
227
+ }
228
+
229
+ function buildSessionDerivedDailyStatistics(date, sessions = readSessionUsage()) {
230
+ const globalEntry = initAggregateEntry('OMP Sessions');
231
+ const byChannel = {};
232
+ const byModel = {};
233
+
234
+ sessions
235
+ .filter(session => getSessionDateKey(session) === date)
236
+ .forEach((session) => {
237
+ const tokens = getSessionUsage(session);
238
+ if (!tokens.total && !tokens.input && !tokens.output && !tokens.reasoning && !tokens.cached) {
239
+ return;
240
+ }
241
+
242
+ addSessionUsage(globalEntry, session);
243
+
244
+ const channelKey = session.provider || 'omp-session';
245
+ if (!byChannel[channelKey]) {
246
+ byChannel[channelKey] = initAggregateEntry(session.provider || 'OMP Session');
247
+ }
248
+ addSessionUsage(byChannel[channelKey], session);
249
+
250
+ const modelKey = session.model || 'unknown';
251
+ if (!byModel[modelKey]) {
252
+ byModel[modelKey] = initAggregateEntry(modelKey);
253
+ }
254
+ addSessionUsage(byModel[modelKey], session);
255
+ });
256
+
257
+ return {
258
+ date,
259
+ source: globalEntry.requests > 0 ? 'sessions' : 'empty',
260
+ summary: {
261
+ requests: globalEntry.requests,
262
+ tokens: globalEntry.tokens.total,
263
+ cost: globalEntry.cost
264
+ },
265
+ byChannel: Object.fromEntries(
266
+ Object.entries(byChannel).map(([key, value]) => [key, toLegacyEntryShape(value, true)])
267
+ ),
268
+ byModel: Object.fromEntries(
269
+ Object.entries(byModel).map(([key, value]) => [key, toLegacyEntryShape(value)])
270
+ )
271
+ };
272
+ }
273
+
274
+ function recordRequest(requestData = {}) {
275
+ const normalizedTokens = normalizeUsageTokens(TOOL_TYPE, requestData.tokens || {});
276
+ return recordSharedRequest({
277
+ ...requestData,
278
+ toolType: TOOL_TYPE,
279
+ tokens: {
280
+ input: normalizedTokens.input,
281
+ output: normalizedTokens.output,
282
+ reasoning: normalizedTokens.reasoning,
283
+ cached: normalizedTokens.cached,
284
+ cacheCreation: normalizedTokens.cacheCreation,
285
+ cacheRead: normalizedTokens.cacheRead,
286
+ total: normalizedTokens.total
287
+ }
288
+ });
289
+ }
290
+
291
+ function getStatistics() {
292
+ const shared = buildSummaryStatistics(getSharedStatistics());
293
+ return hasSummaryData(shared) ? shared : buildSessionDerivedStatistics();
294
+ }
295
+
296
+ function getDailyStatistics(date) {
297
+ const shared = buildDailyStatistics(getSharedDailyStatistics(date), date);
298
+ return hasDailyData(shared) ? shared : buildSessionDerivedDailyStatistics(date);
299
+ }
300
+
301
+ function getTodayStatistics() {
302
+ const shared = buildDailyStatistics(getSharedTodayStatistics());
303
+ return hasDailyData(shared)
304
+ ? shared
305
+ : buildSessionDerivedDailyStatistics(shared.date || new Date().toISOString().slice(0, 10));
306
+ }
307
+
308
+ module.exports = {
309
+ recordRequest,
310
+ getStatistics,
311
+ getDailyStatistics,
312
+ getTodayStatistics,
313
+ _test: {
314
+ buildSessionDerivedStatistics,
315
+ buildSessionDerivedDailyStatistics
316
+ }
317
+ };