coding-tool-x 3.6.6 → 3.6.8

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 (56) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/web/assets/{Analytics-CcGKjDkP.js → Analytics-C57ZRDq5.js} +1 -1
  3. package/dist/web/assets/{ConfigTemplates-DPOa1w5D.js → ConfigTemplates-B3qqqL05.js} +1 -1
  4. package/dist/web/assets/Home-CG5XrTNc.js +1 -0
  5. package/dist/web/assets/Home-CIua-b-o.css +1 -0
  6. package/dist/web/assets/{PluginManager-BVbHUdey.js → PluginManager-BhX0LUzr.js} +1 -1
  7. package/dist/web/assets/{ProjectList-BQrz2FKo.js → ProjectList-BQ01OZn9.js} +1 -1
  8. package/dist/web/assets/{SessionList-CRGer64T.js → SessionList-DPv2IOXG.js} +1 -1
  9. package/dist/web/assets/{SkillManager-BhJKtWYM.js → SkillManager-D5CfQm2O.js} +1 -1
  10. package/dist/web/assets/{WorkspaceManager-pc6tpF3m.js → WorkspaceManager-Ce8ggteK.js} +1 -1
  11. package/dist/web/assets/index-CpnFNWqC.js +2 -0
  12. package/dist/web/assets/index-DJ9VFidd.css +1 -0
  13. package/dist/web/assets/{naive-ui-DM897mIP.js → naive-ui-kcWDeJwl.js} +1 -1
  14. package/dist/web/index.html +3 -3
  15. package/package.json +1 -1
  16. package/src/commands/stats.js +1 -1
  17. package/src/config/channel-preset-websites.js +2 -1
  18. package/src/config/paths.js +8 -0
  19. package/src/server/api/agents.js +16 -54
  20. package/src/server/api/claude-hooks.js +1 -1
  21. package/src/server/api/claude-statistics.js +57 -0
  22. package/src/server/api/commands.js +16 -54
  23. package/src/server/api/dashboard.js +2 -2
  24. package/src/server/api/gemini-channels.js +2 -0
  25. package/src/server/api/hooks.js +4 -1
  26. package/src/server/api/plugins.js +40 -65
  27. package/src/server/api/skills.js +21 -77
  28. package/src/server/api/validation-errors.js +34 -0
  29. package/src/server/gemini-proxy-server.js +205 -21
  30. package/src/server/index.js +1 -0
  31. package/src/server/services/agents-service.js +166 -75
  32. package/src/server/services/base/base-channel-service.js +15 -0
  33. package/src/server/services/base/proxy-utils.js +6 -3
  34. package/src/server/services/base/response-usage-parser.js +44 -0
  35. package/src/server/services/channel-balance.js +86 -1
  36. package/src/server/services/claude-statistics-service.js +139 -0
  37. package/src/server/services/commands-service.js +203 -121
  38. package/src/server/services/config-artifact-paths.js +116 -0
  39. package/src/server/services/config-export-service.js +7 -6
  40. package/src/server/services/config-registry-service.js +2 -2
  41. package/src/server/services/config-sync-manager.js +45 -11
  42. package/src/server/services/config-templates-service.js +21 -19
  43. package/src/server/services/format-converter.js +42 -4
  44. package/src/server/services/gemini-channels.js +30 -1
  45. package/src/server/services/gemini-sessions.js +347 -61
  46. package/src/server/services/mcp-client.js +236 -49
  47. package/src/server/services/mcp-service.js +51 -64
  48. package/src/server/services/notification-hooks.js +659 -88
  49. package/src/server/services/opencode-channels.js +15 -0
  50. package/src/server/services/plugins-service.js +771 -63
  51. package/src/server/services/repo-scanner-base.js +6 -29
  52. package/src/server/services/skill-service.js +187 -63
  53. package/dist/web/assets/Home-BP1LxGtp.js +0 -1
  54. package/dist/web/assets/Home-BeGkC4bb.css +0 -1
  55. package/dist/web/assets/index-0isNzXNY.css +0 -1
  56. package/dist/web/assets/index-BsdIJwLf.js +0 -2
@@ -80,6 +80,19 @@ function forgetBalanceStrategy(key) {
80
80
  }
81
81
  }
82
82
 
83
+ function isRememberedHiddenStrategy(strategy) {
84
+ return strategy?.type === 'unsupported-balance'
85
+ || strategy?.type === 'unavailable-balance';
86
+ }
87
+
88
+ function makeUnavailableBalanceStrategy(snapshot = {}, baseUrl = '') {
89
+ return {
90
+ type: 'unavailable-balance',
91
+ platform: snapshot.platform || null,
92
+ baseUrl: normalizeBaseUrl(baseUrl) || baseUrl || null
93
+ };
94
+ }
95
+
83
96
  function nowIso(now = Date.now()) {
84
97
  return new Date(now).toISOString();
85
98
  }
@@ -1270,6 +1283,12 @@ async function runBalanceStrategy(strategy, token, channel = {}) {
1270
1283
  strategy
1271
1284
  };
1272
1285
  }
1286
+ if (strategy.type === 'unavailable-balance') {
1287
+ return {
1288
+ snapshot: makeHiddenSnapshot(strategy.platform || null),
1289
+ strategy
1290
+ };
1291
+ }
1273
1292
  if (strategy.type === 'siliconflow-user-info') {
1274
1293
  return {
1275
1294
  snapshot: await runSiliconFlowUserInfoStrategy(strategy, token),
@@ -1292,6 +1311,7 @@ async function tryBalanceStrategy(strategy, token, channel = {}) {
1292
1311
 
1293
1312
  async function probeBalanceFromBase(baseUrl, channel, token) {
1294
1313
  let lastSnapshot = null;
1314
+ let lastHiddenStrategy = null;
1295
1315
  for (const strategy of buildBalanceProbeStrategies(baseUrl, channel, token)) {
1296
1316
  const result = await tryBalanceStrategy(strategy, token, channel);
1297
1317
  if (result) return result;
@@ -1304,8 +1324,11 @@ async function probeBalanceFromBase(baseUrl, channel, token) {
1304
1324
  : strategy.platform || null
1305
1325
  );
1306
1326
  }
1327
+ if (isRememberedHiddenStrategy(strategy)) {
1328
+ lastHiddenStrategy = strategy;
1329
+ }
1307
1330
  }
1308
- return lastSnapshot ? { snapshot: lastSnapshot, strategy: null } : null;
1331
+ return lastSnapshot ? { snapshot: lastSnapshot, strategy: lastHiddenStrategy } : null;
1309
1332
  }
1310
1333
 
1311
1334
  function buildCacheKey(source, channel) {
@@ -1341,6 +1364,27 @@ async function refreshChannelBalanceSnapshot(source, channel, options = {}) {
1341
1364
  loadPersistedStrategyCache();
1342
1365
  const cachedStrategy = balanceStrategyCache.get(key);
1343
1366
  if (cachedStrategy) {
1367
+ if (isRememberedHiddenStrategy(cachedStrategy)) {
1368
+ const strategyResult = await runBalanceStrategy(cachedStrategy, token, channel);
1369
+ const hiddenSnapshot = strategyResult?.snapshot || makeHiddenSnapshot(cachedStrategy.platform || null);
1370
+ if (cached?.snapshot?.visible) {
1371
+ const staleSnapshot = {
1372
+ ...cached.snapshot,
1373
+ stale: true
1374
+ };
1375
+ balanceCache.set(key, {
1376
+ snapshot: staleSnapshot,
1377
+ expiresAt: currentTime + CACHE_TTL_MS
1378
+ });
1379
+ return staleSnapshot;
1380
+ }
1381
+ balanceCache.set(key, {
1382
+ snapshot: hiddenSnapshot,
1383
+ expiresAt: currentTime + CACHE_TTL_MS
1384
+ });
1385
+ return hiddenSnapshot;
1386
+ }
1387
+
1344
1388
  const strategyResult = await tryBalanceStrategy(cachedStrategy, token, channel);
1345
1389
  if (strategyResult?.snapshot?.visible) {
1346
1390
  rememberBalanceStrategy(key, strategyResult.strategy);
@@ -1366,6 +1410,13 @@ async function refreshChannelBalanceSnapshot(source, channel, options = {}) {
1366
1410
  lastSnapshot = result?.snapshot || makeHiddenSnapshot(null, { updatedAt: nowIso(currentTime) });
1367
1411
  }
1368
1412
 
1413
+ const hiddenStrategy = lastSnapshot
1414
+ ? makeUnavailableBalanceStrategy(lastSnapshot, bases[0])
1415
+ : null;
1416
+ if (hiddenStrategy) {
1417
+ rememberBalanceStrategy(key, hiddenStrategy);
1418
+ }
1419
+
1369
1420
  if (cached?.snapshot?.visible) {
1370
1421
  const staleSnapshot = {
1371
1422
  ...cached.snapshot,
@@ -1381,6 +1432,38 @@ async function refreshChannelBalanceSnapshot(source, channel, options = {}) {
1381
1432
  return lastSnapshot || makeHiddenSnapshot(null, { updatedAt: nowIso(currentTime) });
1382
1433
  }
1383
1434
 
1435
+ function clearChannelBalanceCache(source, channel) {
1436
+ const normalizedSource = validateSource(source);
1437
+ if (!channel) return;
1438
+ loadPersistedStrategyCache();
1439
+
1440
+ const exactKey = buildCacheKey(normalizedSource, channel);
1441
+ const identity = channel.id || channel.name || 'unknown';
1442
+ const prefix = `${normalizedSource}:${identity}:`;
1443
+ let strategyChanged = false;
1444
+
1445
+ balanceCache.delete(exactKey);
1446
+ for (const key of Array.from(balanceCache.keys())) {
1447
+ if (key.startsWith(prefix)) {
1448
+ balanceCache.delete(key);
1449
+ }
1450
+ }
1451
+
1452
+ if (balanceStrategyCache.delete(exactKey)) {
1453
+ strategyChanged = true;
1454
+ }
1455
+ for (const key of Array.from(balanceStrategyCache.keys())) {
1456
+ if (key.startsWith(prefix)) {
1457
+ balanceStrategyCache.delete(key);
1458
+ strategyChanged = true;
1459
+ }
1460
+ }
1461
+
1462
+ if (strategyChanged) {
1463
+ writePersistedStrategyCache();
1464
+ }
1465
+ }
1466
+
1384
1467
  function getChannelsForSource(source) {
1385
1468
  if (source === 'claude') {
1386
1469
  return require('./channels').getAllChannels() || [];
@@ -1482,8 +1565,10 @@ function clearBalanceCache() {
1482
1565
  module.exports = {
1483
1566
  getChannelBalances,
1484
1567
  refreshChannelBalance,
1568
+ clearChannelBalanceCache,
1485
1569
  _test: {
1486
1570
  clearBalanceCache,
1571
+ clearChannelBalanceCache,
1487
1572
  normalizeBaseUrl,
1488
1573
  buildBaseCandidates,
1489
1574
  buildHubBalanceSnapshot,
@@ -0,0 +1,139 @@
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 = 'claude-code';
10
+ const USAGE_SOURCE = 'claude';
11
+
12
+ function toLegacyEntryShape(entry = {}, includeName = false) {
13
+ const normalized = normalizeUsageTokens(USAGE_SOURCE, entry.tokens || {});
14
+ const result = {
15
+ requests: toNumber(entry.requests),
16
+ tokens: {
17
+ input: normalized.input,
18
+ output: normalized.output,
19
+ cacheCreation: normalized.cacheCreation,
20
+ cacheRead: normalized.cacheRead,
21
+ cached: normalized.cached,
22
+ total: normalized.total
23
+ },
24
+ cost: toNumber(entry.cost)
25
+ };
26
+
27
+ if (includeName) {
28
+ result.name = entry.name || '';
29
+ if (entry.firstUsed) result.firstUsed = entry.firstUsed;
30
+ if (entry.lastUsed) result.lastUsed = entry.lastUsed;
31
+ }
32
+
33
+ return result;
34
+ }
35
+
36
+ function pickToolScope(sharedStats = {}) {
37
+ const byToolType = sharedStats.byToolType || {};
38
+ const toolScope = byToolType[TOOL_TYPE] || {};
39
+
40
+ let byChannel = {};
41
+ let byModel = {};
42
+
43
+ if (toolScope.channels && typeof toolScope.channels === 'object') {
44
+ byChannel = toolScope.channels;
45
+ } else {
46
+ byChannel = Object.fromEntries(
47
+ Object.entries(sharedStats.byChannel || {}).filter(([, value]) => value?.toolType === TOOL_TYPE)
48
+ );
49
+ }
50
+
51
+ if (toolScope.models && typeof toolScope.models === 'object') {
52
+ byModel = toolScope.models;
53
+ } else {
54
+ byModel = Object.fromEntries(
55
+ Object.entries(sharedStats.byModel || {}).filter(([, value]) => value?.toolType === TOOL_TYPE)
56
+ );
57
+ }
58
+
59
+ return { toolScope, byChannel, byModel };
60
+ }
61
+
62
+ function buildSummaryStatistics(sharedStats = {}) {
63
+ const { toolScope, byChannel, byModel } = pickToolScope(sharedStats);
64
+ const normalized = toLegacyEntryShape(toolScope);
65
+
66
+ return {
67
+ version: '1.0',
68
+ lastUpdated: sharedStats.lastUpdated || new Date().toISOString(),
69
+ global: {
70
+ totalRequests: normalized.requests,
71
+ totalTokens: normalized.tokens.total,
72
+ totalCost: normalized.cost
73
+ },
74
+ byChannel: Object.fromEntries(
75
+ Object.entries(byChannel).map(([key, value]) => [key, toLegacyEntryShape(value, true)])
76
+ ),
77
+ byModel: Object.fromEntries(
78
+ Object.entries(byModel).map(([key, value]) => [key, toLegacyEntryShape(value)])
79
+ )
80
+ };
81
+ }
82
+
83
+ function buildDailyStatistics(sharedDaily = {}, fallbackDate) {
84
+ const { byToolType = {} } = sharedDaily;
85
+ const toolScope = byToolType[TOOL_TYPE] || {};
86
+ const normalized = toLegacyEntryShape(toolScope);
87
+ const byChannel = toolScope.channels || {};
88
+ const byModel = toolScope.models || {};
89
+
90
+ return {
91
+ date: sharedDaily.date || fallbackDate,
92
+ summary: {
93
+ requests: normalized.requests,
94
+ tokens: normalized.tokens.total,
95
+ cost: normalized.cost
96
+ },
97
+ byChannel: Object.fromEntries(
98
+ Object.entries(byChannel).map(([key, value]) => [key, toLegacyEntryShape(value, true)])
99
+ ),
100
+ byModel: Object.fromEntries(
101
+ Object.entries(byModel).map(([key, value]) => [key, toLegacyEntryShape(value)])
102
+ )
103
+ };
104
+ }
105
+
106
+ function recordRequest(requestData = {}) {
107
+ const normalizedTokens = normalizeUsageTokens(USAGE_SOURCE, requestData.tokens || {});
108
+ return recordSharedRequest({
109
+ ...requestData,
110
+ toolType: TOOL_TYPE,
111
+ tokens: {
112
+ input: normalizedTokens.input,
113
+ output: normalizedTokens.output,
114
+ cached: normalizedTokens.cached,
115
+ cacheCreation: normalizedTokens.cacheCreation,
116
+ cacheRead: normalizedTokens.cacheRead,
117
+ total: normalizedTokens.total
118
+ }
119
+ });
120
+ }
121
+
122
+ function getStatistics() {
123
+ return buildSummaryStatistics(getSharedStatistics());
124
+ }
125
+
126
+ function getDailyStatistics(date) {
127
+ return buildDailyStatistics(getSharedDailyStatistics(date), date);
128
+ }
129
+
130
+ function getTodayStatistics() {
131
+ return buildDailyStatistics(getSharedTodayStatistics());
132
+ }
133
+
134
+ module.exports = {
135
+ recordRequest,
136
+ getStatistics,
137
+ getDailyStatistics,
138
+ getTodayStatistics
139
+ };