coding-tool-x 3.7.3 → 3.7.5

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 (44) hide show
  1. package/dist/web/assets/{Analytics-BqDjJUJl.js → Analytics-DnnufrQi.js} +1 -1
  2. package/dist/web/assets/{ConfigTemplates-DV2KFuC4.js → ConfigTemplates-BTVhMSfe.js} +1 -1
  3. package/dist/web/assets/Home-CqnBXFxj.css +1 -0
  4. package/dist/web/assets/Home-D03PEREx.js +1 -0
  5. package/dist/web/assets/{PluginManager-Bd3hhc5A.js → PluginManager-BiMqEiyQ.js} +1 -1
  6. package/dist/web/assets/{ProjectList-BB4Whns8.js → ProjectList-C6BA3V49.js} +1 -1
  7. package/dist/web/assets/{ProjectList-D3a0oRum.css → ProjectList-DQ5ZCJO2.css} +1 -1
  8. package/dist/web/assets/SessionList--9Bl6EhV.css +1 -0
  9. package/dist/web/assets/SessionList-DChG04jz.js +1 -0
  10. package/dist/web/assets/{SkillManager-DQjRXOFg.js → SkillManager-DAy8k5CL.js} +1 -1
  11. package/dist/web/assets/{WorkspaceManager-CZeXnxu1.js → WorkspaceManager-Bs2D6R9j.js} +1 -1
  12. package/dist/web/assets/index-DnDBHGCC.js +2 -0
  13. package/dist/web/assets/index-U3TOywtB.css +1 -0
  14. package/dist/web/index.html +2 -2
  15. package/package.json +1 -1
  16. package/src/config/paths.js +2 -0
  17. package/src/server/api/codex-projects.js +22 -9
  18. package/src/server/api/codex-sessions.js +30 -21
  19. package/src/server/api/dashboard.js +174 -94
  20. package/src/server/api/gemini-projects.js +20 -8
  21. package/src/server/api/gemini-sessions.js +28 -26
  22. package/src/server/api/omp-projects.js +19 -7
  23. package/src/server/api/omp-sessions.js +31 -17
  24. package/src/server/api/opencode-projects.js +19 -8
  25. package/src/server/api/opencode-sessions.js +28 -21
  26. package/src/server/api/projects.js +18 -22
  27. package/src/server/api/sessions.js +32 -16
  28. package/src/server/services/channel-balance.js +52 -5
  29. package/src/server/services/codex-sessions.js +23 -10
  30. package/src/server/services/dashboard-snapshot-worker.js +216 -0
  31. package/src/server/services/gemini-sessions.js +15 -3
  32. package/src/server/services/omp-sessions.js +31 -11
  33. package/src/server/services/opencode-sessions.js +9 -6
  34. package/src/server/services/project-snapshots.js +52 -0
  35. package/src/server/services/session-snapshot-worker.js +158 -0
  36. package/src/server/services/session-snapshots.js +137 -0
  37. package/src/server/services/sessions.js +6 -4
  38. package/src/server/services/snapshot-cache.js +361 -0
  39. package/dist/web/assets/Home-D7hovkk9.js +0 -1
  40. package/dist/web/assets/Home-Jom_ZcdY.css +0 -1
  41. package/dist/web/assets/SessionList-CvurKSRK.js +0 -1
  42. package/dist/web/assets/SessionList-D12muXvx.css +0 -1
  43. package/dist/web/assets/index-BovYCFsd.js +0 -2
  44. package/dist/web/assets/index-kQCC5dlu.css +0 -1
@@ -0,0 +1,137 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const { fork } = require('child_process');
5
+ const {
6
+ getSnapshot,
7
+ invalidateSnapshot
8
+ } = require('./snapshot-cache');
9
+
10
+ const SESSION_SNAPSHOT_TTL_MS = 60 * 1000;
11
+ const SESSION_SNAPSHOT_DEFER_MS = process.env.NODE_ENV === 'test' ? 0 : 750;
12
+ const SESSION_SNAPSHOT_WORKER_TIMEOUT_MS = 120 * 1000;
13
+
14
+ function sessionListKey(source, projectName) {
15
+ return `sessions:list:${source}:${projectName}`;
16
+ }
17
+
18
+ function defaultProjectInfo(projectName) {
19
+ return {
20
+ name: projectName,
21
+ fullPath: projectName,
22
+ path: projectName,
23
+ displayName: projectName
24
+ };
25
+ }
26
+
27
+ function emptySessionList(projectName, extra = {}) {
28
+ return {
29
+ sessions: [],
30
+ totalSize: 0,
31
+ aliases: {},
32
+ projectInfo: defaultProjectInfo(projectName),
33
+ ...extra
34
+ };
35
+ }
36
+
37
+ function runSessionSnapshotWorker(source, projectName, config = {}, options = {}) {
38
+ if (process.env.NODE_ENV === 'test') {
39
+ const { buildPayload } = require('./session-snapshot-worker');
40
+ return Promise.resolve(buildPayload({ source, projectName, config, options }));
41
+ }
42
+
43
+ return new Promise((resolve, reject) => {
44
+ const workerPath = path.join(__dirname, 'session-snapshot-worker.js');
45
+ const child = fork(workerPath, [], {
46
+ stdio: ['ignore', 'ignore', 'pipe', 'ipc'],
47
+ env: {
48
+ ...process.env,
49
+ CC_TOOL_SESSION_SNAPSHOT_WORKER: '1'
50
+ }
51
+ });
52
+
53
+ let settled = false;
54
+ let stderr = '';
55
+ let timeout = null;
56
+
57
+ const finish = (error, value) => {
58
+ if (settled) return;
59
+ settled = true;
60
+ if (timeout) {
61
+ clearTimeout(timeout);
62
+ }
63
+ child.removeAllListeners();
64
+ if (!child.killed) {
65
+ child.kill();
66
+ }
67
+ if (error) {
68
+ reject(error);
69
+ } else {
70
+ resolve(value);
71
+ }
72
+ };
73
+
74
+ timeout = setTimeout(() => {
75
+ finish(new Error(`Session snapshot refresh timed out for ${source}/${projectName}`));
76
+ }, SESSION_SNAPSHOT_WORKER_TIMEOUT_MS);
77
+
78
+ child.stderr.on('data', (chunk) => {
79
+ stderr += chunk.toString();
80
+ if (stderr.length > 4096) {
81
+ stderr = stderr.slice(-4096);
82
+ }
83
+ });
84
+
85
+ child.on('message', (message) => {
86
+ if (!message || typeof message !== 'object') return;
87
+ if (message.ok) {
88
+ finish(null, message.value);
89
+ } else {
90
+ finish(new Error(message.error || `Session snapshot refresh failed for ${source}/${projectName}`));
91
+ }
92
+ });
93
+
94
+ child.on('error', (error) => finish(error));
95
+ child.on('exit', (code, signal) => {
96
+ if (settled) return;
97
+ const suffix = stderr ? `: ${stderr.trim()}` : '';
98
+ finish(new Error(`Session snapshot worker exited (${code || signal || 'unknown'})${suffix}`));
99
+ });
100
+
101
+ child.send({ source, projectName, config, options });
102
+ });
103
+ }
104
+
105
+ async function getSessionListSnapshot(source, projectName, {
106
+ fallbackValue,
107
+ refresh,
108
+ force = false
109
+ }) {
110
+ return getSnapshot(sessionListKey(source, projectName), {
111
+ ttlMs: SESSION_SNAPSHOT_TTL_MS,
112
+ fallbackValue: fallbackValue || emptySessionList(projectName),
113
+ refresh,
114
+ force: process.env.NODE_ENV === 'test' ? true : force,
115
+ backgroundOnMiss: process.env.NODE_ENV === 'test' ? false : !force,
116
+ deferMs: SESSION_SNAPSHOT_DEFER_MS
117
+ });
118
+ }
119
+
120
+ function invalidateSessionSnapshots(source, projectName = null) {
121
+ if (!source) return;
122
+ if (projectName) {
123
+ invalidateSnapshot(sessionListKey(source, projectName));
124
+ return;
125
+ }
126
+ invalidateSnapshot(`sessions:list:${source}:`);
127
+ }
128
+
129
+ module.exports = {
130
+ SESSION_SNAPSHOT_TTL_MS,
131
+ defaultProjectInfo,
132
+ emptySessionList,
133
+ getSessionListSnapshot,
134
+ invalidateSessionSnapshots,
135
+ runSessionSnapshotWorker,
136
+ sessionListKey
137
+ };
@@ -600,12 +600,14 @@ function scanSessionFileForMessagesAsync(filePath) {
600
600
  }
601
601
 
602
602
  // Get sessions for a project - async version
603
- async function getSessionsForProject(config, projectName) {
603
+ async function getSessionsForProject(config, projectName, options = {}) {
604
604
  // Check cache first
605
605
  const cacheKey = `${CacheKeys.SESSIONS}${projectName}`;
606
- const cached = globalCache.get(cacheKey);
607
- if (cached) {
608
- return cached;
606
+ if (!options.force) {
607
+ const cached = globalCache.get(cacheKey);
608
+ if (cached) {
609
+ return cached;
610
+ }
609
611
  }
610
612
 
611
613
  const projectConfig = { ...config, currentProject: projectName };
@@ -0,0 +1,361 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const os = require('os');
5
+ const path = require('path');
6
+ const { PATHS } = require('../../config/paths');
7
+
8
+ const DEFAULT_TTL_MS = 60 * 1000;
9
+ const SNAPSHOT_VERSION = 1;
10
+ const DEFAULT_BACKGROUND_DELAY_MS = process.env.NODE_ENV === 'test' ? 0 : 750;
11
+ const DEFAULT_BACKGROUND_GAP_MS = process.env.NODE_ENV === 'test' ? 0 : 100;
12
+
13
+ const snapshots = new Map();
14
+ const inflight = new Map();
15
+ const deferredQueue = [];
16
+ const lastErrors = new Map();
17
+ const invalidationVersions = new Map();
18
+ let deferredRunning = false;
19
+
20
+ function getSnapshotDir() {
21
+ return PATHS.snapshotCache
22
+ || path.join(PATHS.cache || path.join(PATHS.storage || os.tmpdir(), 'cache'), 'snapshots');
23
+ }
24
+
25
+ function cloneJson(value) {
26
+ if (value === undefined) return value;
27
+ try {
28
+ return JSON.parse(JSON.stringify(value));
29
+ } catch {
30
+ return value;
31
+ }
32
+ }
33
+
34
+ function encodeKey(key) {
35
+ return Buffer.from(String(key)).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
36
+ }
37
+
38
+ function getSnapshotPath(key) {
39
+ return path.join(getSnapshotDir(), `${encodeKey(key)}.json`);
40
+ }
41
+
42
+ function normalizeEntry(key, payload) {
43
+ if (!payload || typeof payload !== 'object') return null;
44
+ if (!Object.prototype.hasOwnProperty.call(payload, 'value')) return null;
45
+ const updatedAtMs = Number(payload.updatedAtMs || Date.parse(payload.generatedAt || ''));
46
+ return {
47
+ key,
48
+ value: cloneJson(payload.value),
49
+ generatedAt: payload.generatedAt || (Number.isFinite(updatedAtMs) ? new Date(updatedAtMs).toISOString() : null),
50
+ updatedAtMs: Number.isFinite(updatedAtMs) ? updatedAtMs : 0,
51
+ lastError: typeof payload.lastError === 'string' ? payload.lastError : null
52
+ };
53
+ }
54
+
55
+ function readPersistedSnapshot(key) {
56
+ try {
57
+ const filePath = getSnapshotPath(key);
58
+ if (!fs.existsSync(filePath)) return null;
59
+ const payload = JSON.parse(fs.readFileSync(filePath, 'utf8'));
60
+ return normalizeEntry(key, payload);
61
+ } catch {
62
+ return null;
63
+ }
64
+ }
65
+
66
+ function getEntry(key) {
67
+ if (snapshots.has(key)) {
68
+ return snapshots.get(key);
69
+ }
70
+ const persisted = readPersistedSnapshot(key);
71
+ if (persisted) {
72
+ snapshots.set(key, persisted);
73
+ }
74
+ return persisted;
75
+ }
76
+
77
+ function persistEntry(key, entry) {
78
+ try {
79
+ const filePath = getSnapshotPath(key);
80
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
81
+ const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
82
+ fs.writeFileSync(tempPath, JSON.stringify({
83
+ version: SNAPSHOT_VERSION,
84
+ key,
85
+ value: entry.value,
86
+ generatedAt: entry.generatedAt,
87
+ updatedAtMs: entry.updatedAtMs,
88
+ lastError: entry.lastError || null
89
+ }, null, 2), 'utf8');
90
+ fs.renameSync(tempPath, filePath);
91
+ } catch {
92
+ // Persistence is an optimization; in-memory snapshots still protect the request path.
93
+ }
94
+ }
95
+
96
+ function getInvalidationVersion(key) {
97
+ return invalidationVersions.get(key) || 0;
98
+ }
99
+
100
+ function bumpInvalidationVersion(key) {
101
+ const nextVersion = getInvalidationVersion(key) + 1;
102
+ invalidationVersions.set(key, nextVersion);
103
+ return nextVersion;
104
+ }
105
+
106
+ function makeEntry(key, value, nowMs = Date.now()) {
107
+ return {
108
+ key,
109
+ value: cloneJson(value),
110
+ generatedAt: new Date(nowMs).toISOString(),
111
+ updatedAtMs: nowMs,
112
+ lastError: null
113
+ };
114
+ }
115
+
116
+ function pumpDeferredQueue() {
117
+ if (deferredRunning) return;
118
+ const task = deferredQueue.shift();
119
+ if (!task) return;
120
+
121
+ deferredRunning = true;
122
+ setTimeout(() => {
123
+ Promise.resolve()
124
+ .then(() => task.refresh())
125
+ .then(task.resolve, task.reject)
126
+ .finally(() => {
127
+ deferredRunning = false;
128
+ setTimeout(pumpDeferredQueue, task.gapMs);
129
+ });
130
+ }, task.delayMs);
131
+ }
132
+
133
+ function runDeferredRefresh(refresh, delayMs = DEFAULT_BACKGROUND_DELAY_MS, gapMs = DEFAULT_BACKGROUND_GAP_MS) {
134
+ return new Promise((resolve, reject) => {
135
+ deferredQueue.push({ refresh, resolve, reject, delayMs, gapMs });
136
+ pumpDeferredQueue();
137
+ });
138
+ }
139
+
140
+ function runRefresh(refresh, defer, deferMs) {
141
+ if (!defer) {
142
+ return Promise.resolve().then(() => refresh());
143
+ }
144
+ return runDeferredRefresh(refresh, deferMs);
145
+ }
146
+
147
+ function refreshSnapshot(key, refresh, {
148
+ defer = false,
149
+ deferMs = DEFAULT_BACKGROUND_DELAY_MS,
150
+ bypassInflight = false
151
+ } = {}) {
152
+ if (!bypassInflight && inflight.has(key)) {
153
+ return inflight.get(key);
154
+ }
155
+
156
+ const startedVersion = bypassInflight ? bumpInvalidationVersion(key) : getInvalidationVersion(key);
157
+ const promise = runRefresh(refresh, defer, deferMs)
158
+ .then((value) => {
159
+ const entry = makeEntry(key, value);
160
+ if (getInvalidationVersion(key) === startedVersion) {
161
+ snapshots.set(key, entry);
162
+ lastErrors.delete(key);
163
+ persistEntry(key, entry);
164
+ }
165
+ return entry;
166
+ })
167
+ .catch((error) => {
168
+ const message = error?.message || String(error);
169
+ const existing = getEntry(key);
170
+ if (existing && getInvalidationVersion(key) === startedVersion) {
171
+ const retained = {
172
+ ...existing,
173
+ lastError: message
174
+ };
175
+ snapshots.set(key, retained);
176
+ lastErrors.set(key, message);
177
+ persistEntry(key, retained);
178
+ } else {
179
+ lastErrors.set(key, message);
180
+ }
181
+ throw error;
182
+ })
183
+ .finally(() => {
184
+ if (inflight.get(key) === promise) {
185
+ inflight.delete(key);
186
+ }
187
+ });
188
+
189
+ inflight.set(key, promise);
190
+ promise.catch(() => {});
191
+ return promise;
192
+ }
193
+
194
+ function isExpired(entry, ttlMs, nowMs) {
195
+ if (!entry) return true;
196
+ return nowMs - Number(entry.updatedAtMs || 0) >= ttlMs;
197
+ }
198
+
199
+ function makeMeta(entry, {
200
+ key,
201
+ stale,
202
+ refreshing,
203
+ fallback,
204
+ error
205
+ }) {
206
+ return {
207
+ generatedAt: entry?.generatedAt || null,
208
+ stale: Boolean(stale),
209
+ refreshing: Boolean(refreshing),
210
+ fallback: Boolean(fallback),
211
+ error: error || entry?.lastError || lastErrors.get(entry?.key || key) || null
212
+ };
213
+ }
214
+
215
+ async function getSnapshot(key, {
216
+ ttlMs = DEFAULT_TTL_MS,
217
+ fallbackValue = null,
218
+ refresh,
219
+ backgroundOnMiss = true,
220
+ force = false,
221
+ staleWhileForce = false,
222
+ nowMs = Date.now(),
223
+ deferMs = DEFAULT_BACKGROUND_DELAY_MS
224
+ } = {}) {
225
+ if (typeof refresh !== 'function') {
226
+ const entry = getEntry(key);
227
+ return {
228
+ value: cloneJson(entry ? entry.value : fallbackValue),
229
+ meta: makeMeta(entry, {
230
+ key,
231
+ stale: !entry,
232
+ refreshing: false,
233
+ fallback: !entry
234
+ })
235
+ };
236
+ }
237
+
238
+ let entry = force && !staleWhileForce ? null : getEntry(key);
239
+ let expired = force || isExpired(entry, ttlMs, nowMs);
240
+ let refreshPromise = null;
241
+ let refreshError = null;
242
+
243
+ if (expired) {
244
+ if (!entry && backgroundOnMiss === false) {
245
+ try {
246
+ entry = await refreshSnapshot(key, refresh, { bypassInflight: force });
247
+ expired = false;
248
+ } catch (error) {
249
+ refreshError = error?.message || String(error);
250
+ entry = getEntry(key);
251
+ if (!entry) throw error;
252
+ }
253
+ } else {
254
+ refreshPromise = refreshSnapshot(key, refresh, { defer: true, deferMs, bypassInflight: force });
255
+ }
256
+ }
257
+
258
+ const hasEntry = Boolean(entry);
259
+ return {
260
+ value: cloneJson(hasEntry ? entry.value : fallbackValue),
261
+ meta: makeMeta(entry, {
262
+ key,
263
+ stale: !hasEntry || expired,
264
+ refreshing: Boolean(refreshPromise || inflight.has(key)),
265
+ fallback: !hasEntry,
266
+ error: refreshError
267
+ })
268
+ };
269
+ }
270
+
271
+ function invalidateSnapshot(keyOrPrefix) {
272
+ if (!keyOrPrefix) {
273
+ for (const key of inflight.keys()) {
274
+ bumpInvalidationVersion(key);
275
+ }
276
+ snapshots.clear();
277
+ inflight.clear();
278
+ lastErrors.clear();
279
+ return;
280
+ }
281
+
282
+ const key = String(keyOrPrefix);
283
+ snapshots.delete(key);
284
+ inflight.delete(key);
285
+ lastErrors.delete(key);
286
+ bumpInvalidationVersion(key);
287
+ for (const existingKey of Array.from(snapshots.keys())) {
288
+ if (existingKey.startsWith(key)) {
289
+ snapshots.delete(existingKey);
290
+ lastErrors.delete(existingKey);
291
+ bumpInvalidationVersion(existingKey);
292
+ }
293
+ }
294
+ for (const existingKey of Array.from(inflight.keys())) {
295
+ if (existingKey.startsWith(key)) {
296
+ inflight.delete(existingKey);
297
+ lastErrors.delete(existingKey);
298
+ bumpInvalidationVersion(existingKey);
299
+ }
300
+ }
301
+
302
+ try {
303
+ const dir = getSnapshotDir();
304
+ if (!fs.existsSync(dir)) return;
305
+ const exactFile = getSnapshotPath(key);
306
+ if (fs.existsSync(exactFile)) {
307
+ fs.unlinkSync(exactFile);
308
+ }
309
+ const files = fs.readdirSync(dir).filter(file => file.endsWith('.json'));
310
+ files.forEach((file) => {
311
+ const filePath = path.join(dir, file);
312
+ try {
313
+ const payload = JSON.parse(fs.readFileSync(filePath, 'utf8'));
314
+ const persistedKey = typeof payload?.key === 'string' ? payload.key : '';
315
+ if (persistedKey && persistedKey.startsWith(key)) {
316
+ fs.unlinkSync(filePath);
317
+ lastErrors.delete(persistedKey);
318
+ bumpInvalidationVersion(persistedKey);
319
+ }
320
+ } catch {
321
+ // Corrupt non-exact files cannot be matched to a prefix safely.
322
+ }
323
+ });
324
+ } catch {
325
+ // Best-effort invalidation; the in-memory state has already been cleared.
326
+ }
327
+ }
328
+
329
+ function clearSnapshotCache({ deleteFiles = false } = {}) {
330
+ for (const key of inflight.keys()) {
331
+ bumpInvalidationVersion(key);
332
+ }
333
+ snapshots.clear();
334
+ inflight.clear();
335
+ lastErrors.clear();
336
+ deferredQueue.splice(0, deferredQueue.length);
337
+ deferredRunning = false;
338
+ if (!deleteFiles) return;
339
+ try {
340
+ fs.rmSync(getSnapshotDir(), { recursive: true, force: true });
341
+ } catch {
342
+ // ignore cleanup failures in tests
343
+ }
344
+ }
345
+
346
+ module.exports = {
347
+ getSnapshot,
348
+ refreshSnapshot,
349
+ invalidateSnapshot,
350
+ clearSnapshotCache,
351
+ _test: {
352
+ getSnapshotDir,
353
+ getSnapshotPath,
354
+ encodeKey,
355
+ readPersistedSnapshot,
356
+ getEntry,
357
+ inflight,
358
+ snapshots,
359
+ deferredQueue
360
+ }
361
+ };
@@ -1 +0,0 @@
1
- import{d as e}from"./vendors-DQA4Hw9v.js";import{r as a,a8 as l,f as n,w as s,h as c,K as t,a7 as o,c as i,o as u,a as r,W as d,a0 as v,X as p,Y as h,N as y,a3 as m,_ as g,p as f,R as k,L as T,F as C,$ as w,Z as b,v as x}from"./vue-vendor-B5RqjEjQ.js";import{g as $,u as _,a as S,s as z,D as q,_ as P,b as j,c as L,d as M,R as I,e as O,f as E,h as N,i as F,j as A,k as D,l as U,m as J,n as V,o as R,p as K}from"./index-BovYCFsd.js";import{h as B,ar as Z,E as G,P as H,as as W,at as X,au as Y,av as Q,aa as ee,i as ae,A as le,aw as ne,ax as se,T as ce,a as te,b as oe}from"./icons-nGdSKQn2.js";import{L as ie,N as ue,B as re,s as de,b as ve,c as pe,a as he,Z as ye}from"./naive-ui-CVyvdmg1.js";import"./markdown-BNJfEgCA.js";const me=a({theme:"light",panelVisibility:{showChannels:!0,showLogs:!0},channelBalance:{showRemaining:!1},channelLocks:{claude:!1,codex:!1,gemini:!1,opencode:!1,omp:!1},channelCollapse:{claude:[],codex:[],gemini:[],opencode:[],omp:[]},channelOrder:{claude:[],codex:[],gemini:[],opencode:[],omp:[]},dashboardChannelOrder:q,homeCliColumns:q,customCliPlatforms:[]});let ge=!1,fe=null;async function ke(){return ge?me.value:fe||(fe=(async()=>{try{const e=await $();e.success&&e.config&&(me.value=e.config,ge=!0)}catch(e){}finally{fe=null}return me.value})(),fe)}function Te(){return ge||ke(),{uiConfig:me,loadUIConfig:ke,saveConfig:async function(e){try{const a=await z(e);return!!a.success&&(me.value=a.config,!0)}catch(a){return!1}},updateConfig:async function(e,a){try{const l=await S(e,a);return!!l.success&&(me.value=l.config,!0)}catch(l){return!1}},updateNestedConfig:async function(e,a,l){try{const n=await _(e,a,l);return!!n.success&&(me.value=n.config,!0)}catch(n){return!1}}}}const Ce={class:"channel-column"},we={class:"drag-handle",title:"拖拽排序"},be={class:"header-icon"},xe={class:"channel-title"},$e={key:0,class:"claude-extra-area"},_e={key:0,class:"channel-content"},Se={key:0,class:"card"},ze={class:"card-header"},qe={key:0,class:"runtime-badge"},Pe={class:"card-body",style:{padding:"6px 10px"}},je={class:"proxy-info-row"},Le={class:"proxy-status"},Me={class:"proxy-port"},Ie={class:"channel-name"},Oe={class:"channel-quick-panel"},Ee={class:"panel-title"},Ne={key:0,class:"no-channels"},Fe={key:1,class:"channel-quick-list"},Ae={class:"channel-quick-info"},De={class:"channel-quick-name"},Ue={key:0,class:"channel-switching-tip"},Je={class:"channel-metrics"},Ve={class:"metric-item"},Re={class:"metric-value"},Ke={class:"metric-item"},Be={class:"metric-value"},Ze={class:"metric-item"},Ge={class:"metric-value"},He={class:"metric-item"},We={class:"card"},Xe={class:"card-header compact"},Ye={class:"card-body",style:{padding:"8px 10px"}},Qe={class:"quick-access-list"},ea={class:"access-icon"},aa={class:"access-content"},la={class:"access-value"},na={class:"access-icon"},sa={class:"access-content"},ca={class:"access-value"},ta={class:"access-icon"},oa={class:"access-content"},ia={class:"access-goto"},ua={class:"card-header compact"},ra={class:"card-body",style:{padding:"8px 10px"}},da={class:"stats-inline stats-3col"},va={class:"stat-inline-item stat-requests"},pa={class:"stat-info"},ha={class:"stat-inline-item stat-input"},ya={class:"stat-info"},ma={class:"stat-inline-item stat-output"},ga={class:"stat-info"},fa={key:2,class:"card logs-card"},ka={class:"card-header compact"},Ta={class:"card-body logs-card-body"},Ca={class:"logs-table-wrapper"},wa={key:0,class:"empty-logs"},ba=["title"],xa={key:0,class:"action-content"},$a={class:"action-msg"},_a={class:"action-time"},Sa={key:1,class:"action-content"},za={class:"action-msg error-msg"},qa={class:"action-time error-time"},Pa={class:"locked-content"},ja={class:"lock-icon"},La="channelLocks",Ma=P({__name:"ChannelColumn",props:{channelType:{type:String,required:!0}},setup(e){const S=e,z=l(),q=ie(),{uiConfig:P}=Te(),{claudeProxy:K,codexProxy:me,geminiProxy:ge,opencodeProxy:fe,ompProxy:ke,claudeChannels:Ma,codexChannels:Ia,geminiChannels:Oa,opencodeChannels:Ea,ompChannels:Na,schedulerState:Fa,getProxyState:Aa,startProxy:Da,stopProxy:Ua,getLogs:Ja,clearLogsForSource:Va,loadChannels:Ra,logLimit:Ka,statsInterval:Ba}=j(),{dashboardData:Za,loadDashboard:Ga}=L(),Ha=n(()=>M(S.channelType,P.value.customCliPlatforms)),Wa=n(()=>Ha.value.title||Ha.value.label||S.channelType),Xa=n(()=>Ha.value.icon||B),Ya=n(()=>Ha.value.color||"#64748b"),Qa=n(()=>"claude"===S.channelType?K.value:"codex"===S.channelType?me.value:"gemini"===S.channelType?ge.value:"opencode"===S.channelType?fe.value:"omp"===S.channelType?ke.value:Ha.value.custom?{running:!1,loading:!1,activeChannel:null,port:null,runtime:null,startTime:null}:{}),el=n(()=>"claude"===S.channelType?"Claude":"codex"===S.channelType?"Codex":"gemini"===S.channelType?"Gemini":"opencode"===S.channelType?"OpenCode":"omp"===S.channelType?"OMP":Ha.value.label||S.channelType),al=a({projects:0,sessions:0}),ll=a({requests:0,tokens:0,cost:0}),nl=a({requests:0,tokens:0,cost:0}),sl={requests:0,tokens:0,cost:3};let cl={requests:null,tokens:null,cost:null};const tl=a({requests:!1,tokens:!1,cost:!1}),ol=n(()=>{var e,a,l;return(null==(l=null==(a=null==(e=Za.value)?void 0:e.todayStats)?void 0:a[S.channelType])?void 0:l.byModel)||{}});function il(e,a,l,n=600){cl[e]&&cancelAnimationFrame(cl[e]),tl.value[e]=!0;const s=Date.now(),c=()=>{const t=Date.now()-s,o=Math.min(t/n,1),i=1-Math.pow(1-o,2),u=a+(l-a)*i,r=sl[e]??0,d=Math.pow(10,r),v=r>0?Math.round(u*d)/d:Math.round(u);nl.value[e]=v,o<1?cl[e]=requestAnimationFrame(c):tl.value[e]=!1};cl[e]=requestAnimationFrame(c)}const ul=a(!1),rl={claude:"claudeChannelCollapse",codex:"codexChannelCollapse",gemini:"geminiChannelCollapse",opencode:"opencodeChannelCollapse",omp:"ompChannelCollapse"};function dl(e){try{const a=localStorage.getItem(La),l=a?JSON.parse(a):{};l[S.channelType]=e,localStorage.setItem(La,JSON.stringify(l))}catch(a){}}const vl=a(function(){try{const e=localStorage.getItem(La);if(e){return JSON.parse(e)[S.channelType]||!1}}catch(e){}return!1}());async function pl(){vl.value=!vl.value,dl(vl.value);try{if(await _("channelLocks",S.channelType,vl.value),Za.value){const e=Za.value.uiConfig||{},a={...e.channelLocks||{}};a[S.channelType]=vl.value,Za.value={...Za.value,uiConfig:{...e,channelLocks:a}}}}catch(e){}}const hl=a(!0);function yl(e){e.detail&&void 0!==e.detail.showLogs&&(hl.value=e.detail.showLogs)}const ml=a(Date.now()),gl=n(()=>{if(!Qa.value.running)return"";const e=Qa.value.startTime;if(!e)return"";const a=ml.value-e;if(a<=0)return"";const l=Math.floor(a/1e3),n=Math.floor(l/3600),s=Math.floor(l%3600/60),c=l%60;let t="已运行 ";return n>0&&(t+=`${n}小时`),s>0&&(t+=`${s}分`),(c>0||0===n&&0===s)&&(t+=`${c}秒`),t}),fl=a(null),kl=n(()=>Ka.value),Tl={claude:Ja("claude"),codex:Ja("codex"),gemini:Ja("gemini"),opencode:Ja("opencode"),omp:Ja("omp")},Cl=n(()=>{if(!Il())return[];return((Tl[S.channelType]||Tl.claude).value||[]).slice(0,kl.value)});let wl=null,bl=null,xl=null,$l=!1,_l=null;const Sl=n(()=>{let e=[];"claude"===S.channelType?e=Ma.value||[]:"codex"===S.channelType?e=Ia.value||[]:"gemini"===S.channelType?e=Oa.value||[]:"opencode"===S.channelType?e=Ea.value||[]:"omp"===S.channelType&&(e=Na.value||[]);return[...e.filter(e=>!1!==e.enabled),...e.filter(e=>!1===e.enabled)]});function zl(e){const a=Fa[S.channelType];if(!a||!a.channels)return 0;const l=a.channels.find(a=>a.id===e);return l?l.inflight:0}const ql=n(()=>{const e=Sl.value.filter(e=>!1!==e.enabled).length;return Qa.value.running?`${e}个渠道调度中`:Sl.value.length>0?`${e}个渠道已启用`:"无渠道"}),Pl=a({});function jl(e){return Pl.value[e]||{requests:0,tokens:0,cost:0}}async function Ll(){var e;try{let a;if("claude"===S.channelType?a=await O():"codex"===S.channelType?a=await E():"gemini"===S.channelType?a=await N():"opencode"===S.channelType?a=await F():"omp"===S.channelType&&(a=await A()),a&&a.byChannel){const l={};for(const[n,s]of Object.entries(a.byChannel))l[n]={requests:s.requests||0,tokens:(null==(e=s.tokens)?void 0:e.total)||0,cost:s.cost||0};Pl.value=l}}catch(a){}}function Ml(e,a){var l;return(null==e?void 0:e.usageMissing)?"--":(null==(l=null==e?void 0:e.tokens)?void 0:l[a])||0}function Il(){return["claude","codex","gemini","opencode","omp"].includes(S.channelType)}function Ol(e){if(!e||"action"===e.type||"error"===e.status)return"";const a=[];return e.model&&a.push(`模型: ${e.model}`),e.originalModel&&e.originalModel!==e.model&&a.push(`重定向: ${e.originalModel} -> ${e.model}`),e.usageMissing&&a.push("上游响应未返回 usage,当前无法计算 token。"),a.join("\n")}async function El(e){var a,l;if(!1===Ha.value.supportsProxy||!Il())return void q.warning(`${Wa.value} 暂未接入动态代理`);const n=Aa(S.channelType);n.value.loading=!0;try{let a;a=e?await Da(S.channelType):await Ua(S.channelType,{refreshChannelsDrawer:!0}),!1!==a.success?q.success(e?`${Wa.value} 代理已启动`:`${Wa.value} 代理已停止`):(q.error(a.error||"操作失败"),n.value.running=!e)}catch(s){q.error((null==(l=null==(a=s.response)?void 0:a.data)?void 0:l.error)||s.message||"操作失败"),n.value.running=!e}finally{n.value.loading=!1}}function Nl(){!1!==Ha.value.supportsProjects&&Il()?z.push({name:`${S.channelType}-projects`}):q.info(`${Wa.value} 当前仅作为首页显示项`)}function Fl(){!1!==Ha.value.supportsProjects&&Il()?z.push({name:`${S.channelType}-projects`}):q.info(`${Wa.value} 当前仅作为首页显示项`)}function Al(){!1!==Ha.value.supportsSessions&&Il()?ul.value=!0:q.info(`${Wa.value} 当前没有托管会话列表`)}s(Cl,e=>{var a;const l=(null==(a=e[0])?void 0:a.id)||null;if(!l||l===wl)return void(wl=l);wl=l,_l&&clearTimeout(_l),_l=setTimeout(()=>{Ll()},5e3);(!fl.value||fl.value.scrollTop<20)&&x(()=>{fl.value&&(fl.value.scrollTop=0)})}),s(()=>ll.value.requests,e=>{il("requests",nl.value.requests,e,600)}),s(()=>ll.value.tokens,e=>{il("tokens",nl.value.tokens,e,600)}),s(()=>ll.value.cost,e=>{il("cost",nl.value.cost,e,600)}),s(()=>S.channelType,()=>{var e;wl=(null==(e=Cl.value[0])?void 0:e.id)||null}),s(()=>{var e,a;return null==(a=null==(e=Za.value)?void 0:e.counts)?void 0:a[S.channelType]},()=>{Rl()}),s(Ba,()=>{$l&&function(){bl&&(clearInterval(bl),bl=null);const e=Ba.value||30,a=Math.max(1e3*e,1e4);bl=setInterval(()=>{Kl(),Ll()},a)}()});const Dl=a({});function Ul(e){return!!Dl.value[e]}function Jl(e,a){e&&(Dl.value={...Dl.value,[e]:!!a})}async function Vl(e,a){if(e&&!Ul(e.id)){Jl(e.id,!0);try{let l;"claude"===S.channelType?l=D:"codex"===S.channelType?l=U:"gemini"===S.channelType?l=J:"opencode"===S.channelType?l=V:"omp"===S.channelType&&(l=R),l&&(await l(e.id,{enabled:a}),await async function(e,a){if(!e)return;const l=rl[S.channelType];let n={};try{const e=l?localStorage.getItem(l):null;n=e?JSON.parse(e):{}}catch(s){n={}}a?delete n[e]:n[e]=!0;try{l&&localStorage.setItem(l,JSON.stringify(n))}catch(s){}try{await _("channelCollapse",S.channelType,n)}catch(s){}}(e.id,a),q.success(a?`渠道「${e.name}」已启用`:`渠道「${e.name}」已停用`),await Ra(),window.dispatchEvent(new CustomEvent("channel-management-refresh",{detail:{channel:S.channelType}})))}catch(l){q.error("操作失败: "+l.message)}finally{Jl(e.id,!1)}}}function Rl(){var e,a;const l=null==(a=null==(e=Za.value)?void 0:e.counts)?void 0:a[S.channelType];al.value.projects=(null==l?void 0:l.projectCount)||0,al.value.sessions=(null==l?void 0:l.sessionCount)||0}async function Kl(){if(Za.value&&Za.value.todayStats){const e=Za.value.todayStats[S.channelType];e&&(ll.value.requests=e.requests||0,ll.value.tokens=e.tokens||0,ll.value.cost=e.cost||0)}Rl()}function Bl(){Va(S.channelType)}function Zl(e){var a,l;null==(l=null==(a=null==e?void 0:e.currentTarget)?void 0:a.blur)||l.call(a)}function Gl(e){window.dispatchEvent(new CustomEvent("open-skills-drawer",{detail:{platform:S.channelType}})),Zl(e)}function Hl(e){window.dispatchEvent(new CustomEvent("open-commands-drawer",{detail:{platform:S.channelType}})),Zl(e)}function Wl(e){if(!1===Ha.value.supportsAgents)return q.info(`${Wa.value} 的 Agent 能力通过插件/扩展提供`),void Zl(e);window.dispatchEvent(new CustomEvent("open-agents-drawer",{detail:{platform:S.channelType}})),Zl(e)}return c(async()=>{await Promise.all([Ga().then(()=>Kl()),Ll()]),async function(){var e,a;try{if(Za.value&&Za.value.uiConfig)hl.value=!1!==(null==(e=Za.value.uiConfig.panelVisibility)?void 0:e.showLogs);else{const e=await $();e.success&&e.config&&(hl.value=!1!==(null==(a=e.config.panelVisibility)?void 0:a.showLogs))}}catch(l){}}(),async function(){var e,a;try{let l=!1;if(Za.value&&Za.value.uiConfig)l=(null==(e=Za.value.uiConfig.channelLocks)?void 0:e[S.channelType])||!1;else{const e=await $();e.success&&e.config&&(l=(null==(a=e.config.channelLocks)?void 0:a[S.channelType])||!1)}vl.value=l,dl(l)}catch(l){}}(),window.addEventListener("panel-visibility-change",yl),nl.value={...ll.value},$l=!0,xl=setInterval(()=>{ml.value=Date.now()},1e3)}),t(()=>{$l=!1,bl&&clearInterval(bl),xl&&clearInterval(xl),_l&&clearTimeout(_l),window.removeEventListener("panel-visibility-change",yl),Object.values(cl).forEach(e=>{e&&cancelAnimationFrame(e)})}),(a,l)=>{const n=o("n-collapse");return u(),i("div",Ce,[r("div",{class:T(["channel-header",[e.channelType,{"custom-cli":Ha.value.custom}]]),style:k(Ha.value.custom?{"--channel-accent":Ya.value}:null)},[r("div",we,[p(y(ue),{size:16},{default:h(()=>[p(y(Z))]),_:1})]),r("div",be,[p(y(ue),{size:20},{default:h(()=>[(u(),v(m(Xa.value)))]),_:1})]),r("h2",xe,g(Wa.value),1),!1!==Ha.value.supportsManagedConfig?(u(),i("div",$e,[p(y(de),{trigger:"hover"},{trigger:h(()=>[p(y(re),{text:"",class:"config-shortcut-button",onClick:Gl,title:"Skills 技能管理"},{icon:h(()=>[p(y(ue),{size:18},{default:h(()=>[p(y(G))]),_:1})]),_:1})]),default:h(()=>[l[2]||(l[2]=f(" Skills 技能管理 ",-1))]),_:1}),p(y(de),{trigger:"hover"},{trigger:h(()=>[p(y(re),{text:"",class:"config-shortcut-button",onClick:Hl,title:"Commands 命令管理"},{icon:h(()=>[p(y(ue),{size:18},{default:h(()=>[p(y(B))]),_:1})]),_:1})]),default:h(()=>[l[3]||(l[3]=f(" Commands 命令管理 ",-1))]),_:1}),!1!==Ha.value.supportsAgents?(u(),v(y(de),{key:0,trigger:"hover"},{trigger:h(()=>[p(y(re),{text:"",class:"config-shortcut-button",onClick:Wl,title:"Agents 代理管理"},{icon:h(()=>[p(y(ue),{size:18},{default:h(()=>[p(y(H))]),_:1})]),_:1})]),default:h(()=>[l[4]||(l[4]=f(" Agents 代理管理 ",-1))]),_:1})):d("",!0)])):d("",!0),p(y(re),{text:"",class:"lock-button",onClick:pl,title:vl.value?"解锁此列":"锁定此列"},{icon:h(()=>[p(y(ue),{size:18},{default:h(()=>[vl.value?(u(),v(y(W),{key:0})):(u(),v(y(X),{key:1}))]),_:1})]),_:1},8,["title"])],6),vl.value?d("",!0):(u(),i("div",_e,[!1!==Ha.value.supportsProxy?(u(),i("div",Se,[r("div",ze,[p(y(ue),{size:16},{default:h(()=>[p(y(Y))]),_:1}),l[5]||(l[5]=r("h3",{class:"card-title"},"代理控制",-1)),Qa.value.running&&gl.value?(u(),i("span",qe,g(gl.value),1)):d("",!0),p(y(ve),{value:Qa.value.running,"onUpdate:value":[l[0]||(l[0]=e=>Qa.value.running=e),El],loading:Qa.value.loading,size:"small",style:{"margin-left":"auto"}},null,8,["value","loading"])]),r("div",Pe,[r("div",je,[r("div",Le,[r("div",{class:T(["status-dot",{active:Qa.value.running}])},null,2),p(y(pe),{type:Qa.value.running?"success":"default",style:{"font-size":"12px"}},{default:h(()=>[f(g(Qa.value.running?"运行中":"已停止"),1)]),_:1},8,["type"]),r("span",Me,"端口: "+g(Qa.value.port),1)]),p(y(ye),{trigger:"click",placement:"bottom",width:320,class:"channel-popover"},{trigger:h(()=>[p(y(re),{text:"",size:"tiny",class:"channel-status"},{default:h(()=>[r("span",Ie,g(ql.value),1)]),_:1})]),default:h(()=>[r("div",Oe,[r("div",Ee,[l[7]||(l[7]=r("span",null,"渠道快捷管理",-1)),p(y(pe),{depth:"3",style:{"font-size":"11px"}},{default:h(()=>[...l[6]||(l[6]=[f("点击开关切换状态",-1)])]),_:1})]),0===Sl.value.length?(u(),i("div",Ne,[p(y(pe),{depth:"3"},{default:h(()=>[...l[8]||(l[8]=[f("暂无配置渠道",-1)])]),_:1})])):(u(),i("div",Fe,[(u(!0),i(C,null,w(Sl.value,e=>{var a,n;return u(),i("div",{key:e.id,class:T(["channel-quick-item",{disabled:!1===e.enabled}])},[r("div",Ae,[r("span",De,g(e.name),1),"frozen"===(null==(a=e.health)?void 0:a.status)?(u(),v(y(he),{key:0,size:"tiny",type:"error",bordered:!1},{default:h(()=>[...l[9]||(l[9]=[f(" 冻结 ",-1)])]),_:1})):d("",!0),p(y(ve),{size:"small",value:!1!==e.enabled,"onUpdate:value":a=>Vl(e,a),loading:Ul(e.id),disabled:Ul(e.id),style:{"margin-left":"auto"}},null,8,["value","onUpdate:value","loading","disabled"])]),Ul(e.id)?(u(),i("div",Ue," 正在切换渠道状态... ")):d("",!0),r("div",Je,[r("span",Ve,[l[10]||(l[10]=r("span",{class:"metric-label"},"请求",-1)),r("span",Re,g(jl(e.id).requests),1)]),r("span",Ke,[l[11]||(l[11]=r("span",{class:"metric-label"},"Tokens",-1)),r("span",Be,g((n=jl(e.id).tokens,n>=1e6?(n/1e6).toFixed(1)+"M":n>=1e3?(n/1e3).toFixed(1)+"K":n.toString())),1)]),r("span",Ze,[l[12]||(l[12]=r("span",{class:"metric-label"},"权重",-1)),r("span",Ge,g(e.weight||1),1)]),r("span",He,[l[13]||(l[13]=r("span",{class:"metric-label"},"并发",-1)),r("span",{class:T(["metric-value",{active:zl(e.id)>0}])},g(zl(e.id))+g(e.maxConcurrency?`/${e.maxConcurrency}`:""),3)])])],2)}),128))]))])]),_:1})])])])):d("",!0),r("div",We,[r("div",Xe,[p(y(ue),{size:14},{default:h(()=>[p(y(Q))]),_:1}),l[14]||(l[14]=r("h3",{class:"card-title"},"快速访问",-1))]),r("div",Ye,[r("div",Qe,[r("div",{class:T(["access-card access-card-projects",{clickable:!1!==Ha.value.supportsProjects,disabled:!1===Ha.value.supportsProjects}]),onClick:Nl},[r("div",ea,[p(y(ue),{size:16},{default:h(()=>[p(y(ee))]),_:1})]),r("div",aa,[l[15]||(l[15]=r("span",{class:"access-label"},"项目",-1)),r("span",la,g(al.value.projects),1)])],2),r("div",{class:T(["access-card access-card-sessions",{clickable:!1!==Ha.value.supportsSessions,disabled:!1===Ha.value.supportsSessions}]),onClick:Al},[r("div",na,[p(y(ue),{size:16},{default:h(()=>[p(y(ae))]),_:1})]),r("div",sa,[l[16]||(l[16]=r("span",{class:"access-label"},"最新对话",-1)),r("span",ca,g(al.value.sessions),1)])],2),r("div",{class:T(["access-card access-card-goto",{clickable:!1!==Ha.value.supportsProjects,disabled:!1===Ha.value.supportsProjects}]),onClick:Fl},[r("div",ta,[p(y(ue),{size:16},{default:h(()=>[p(y(le))]),_:1})]),r("div",oa,[l[17]||(l[17]=r("span",{class:"access-label"},"前往",-1)),r("span",ia,g(el.value),1)])],2)])])]),r("div",{class:T(["card stats-card",`stats-card-${e.channelType}`])},[r("div",ua,[p(y(ue),{size:14},{default:h(()=>[p(y(ne))]),_:1}),l[18]||(l[18]=r("h3",{class:"card-title"},"今日数据",-1))]),r("div",ra,[r("div",da,[r("div",va,[l[20]||(l[20]=r("div",{class:"stat-icon-dot requests"},null,-1)),r("div",pa,[l[19]||(l[19]=r("span",{class:"stat-label"},"请求",-1)),r("span",{class:T(["stat-value",{animating:tl.value.requests}])},g(nl.value.requests),3)])]),r("div",ha,[l[22]||(l[22]=r("div",{class:"stat-icon-dot tokens"},null,-1)),r("div",ya,[l[21]||(l[21]=r("span",{class:"stat-label"},"总 Tokens",-1)),r("span",{class:T(["stat-value",{animating:tl.value.tokens}])},g((c=nl.value.tokens,c>=1e6?(c/1e6).toFixed(1)+"M":c>=1e3?(c/1e3).toFixed(1)+"K":c.toString())),3)])]),r("div",ma,[l[24]||(l[24]=r("div",{class:"stat-icon-dot cost"},null,-1)),r("div",ga,[l[23]||(l[23]=r("span",{class:"stat-label"},"成本 / USD",-1)),r("span",{class:T(["stat-value",{animating:tl.value.cost}])},g((s=nl.value.cost,!s||Number.isNaN(s)?"$0":"$"+Number(s).toFixed(3))),3)])])])])],2),Object.keys(ol.value).length>0?(u(),i("div",{key:1,class:T(["card chart-card",`chart-card-${e.channelType}`])},[p(n,{"default-expanded-names":[],accordion:""})],2)):d("",!0),hl.value?(u(),i("div",fa,[r("div",ka,[p(y(ue),{size:14},{default:h(()=>[p(y(se))]),_:1}),l[25]||(l[25]=r("h3",{class:"card-title"},"实时日志",-1)),p(y(re),{text:"",size:"tiny",onClick:b(Bl,["stop"]),style:{"margin-left":"auto"},title:"清空日志"},{icon:h(()=>[p(y(ue),{size:14},{default:h(()=>[p(y(ce))]),_:1})]),_:1})]),r("div",Ta,[r("div",Ca,[r("div",{class:T(["logs-table-header",`logs-header-${e.channelType}`])},[r("div",{class:T(["log-col col-channel",`col-channel-${e.channelType}`])},"渠道",2),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},"请求",2),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},"回复",2),"claude"===e.channelType?(u(),i(C,{key:0},[r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},"写入",2),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},"命中",2)],64)):"codex"===e.channelType?(u(),i(C,{key:1},[r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},"推理",2),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},"缓存",2),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},"总计",2)],64)):"gemini"===e.channelType?(u(),i(C,{key:2},[r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},"缓存",2),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},"总计",2)],64)):"opencode"===e.channelType||"omp"===e.channelType?(u(),i(C,{key:3},[r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},"推理",2),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},"缓存",2),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},"总计",2)],64)):d("",!0),r("div",{class:T(["log-col col-time",`col-time-${e.channelType}`])},"时间",2)],2),r("div",{class:"logs-container",ref_key:"logsContainer",ref:fl},[0===Cl.value.length?(u(),i("div",wa,[p(y(ue),{size:32,depth:"3",style:{"margin-bottom":"8px"}},{default:h(()=>[p(y(se))]),_:1}),p(y(pe),{depth:"3",style:{"font-size":"12px","font-weight":"500"}},{default:h(()=>[...l[26]||(l[26]=[f("暂无实时日志",-1)])]),_:1}),p(y(pe),{depth:"3",style:{"font-size":"11px","margin-top":"4px"}},{default:h(()=>[...l[27]||(l[27]=[f("开启代理后将显示请求记录",-1)])]),_:1})])):d("",!0),(u(!0),i(C,null,w(Cl.value,a=>(u(),i("div",{key:a.id,class:T(["log-row",{"action-row":"action"===a.type,"error-row":"error"===a.status,"new-log":a.isNew}]),title:Ol(a)},["action"===a.type?(u(),i("div",xa,[p(y(ue),{size:12,color:"#18a058"},{default:h(()=>[p(y(te))]),_:1}),r("span",$a,g(a.message),1),r("span",_a,g(a.time),1)])):"error"===a.status?(u(),i("div",Sa,[p(y(ue),{size:12,color:"#d03050"},{default:h(()=>[p(y(oe))]),_:1}),r("span",za,g(a.channel)+": "+g(a.error||a.message||"请求失败"),1),r("span",qa,g(a.time),1)])):(u(),i(C,{key:2},[r("div",{class:T(["log-col col-channel",`col-channel-${e.channelType}`])},[p(y(he),{size:"tiny",type:"success"},{default:h(()=>[f(g(a.channel),1)]),_:2},1024)],2),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},g(Ml(a,"input")),3),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},g(Ml(a,"output")),3),"claude"===e.channelType?(u(),i(C,{key:0},[r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},g(Ml(a,"cacheCreation")),3),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},g(Ml(a,"cacheRead")),3)],64)):"codex"===e.channelType?(u(),i(C,{key:1},[r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},g(Ml(a,"reasoning")),3),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},g(Ml(a,"cached")),3),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},g(Ml(a,"total")),3)],64)):"gemini"===e.channelType?(u(),i(C,{key:2},[r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},g(Ml(a,"cached")),3),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},g(Ml(a,"total")),3)],64)):"opencode"===e.channelType||"omp"===e.channelType?(u(),i(C,{key:3},[r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},g(Ml(a,"reasoning")),3),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},g(Ml(a,"cached")),3),r("div",{class:T(["log-col col-token",`col-token-${e.channelType}`])},g(Ml(a,"total")),3)],64)):d("",!0),r("div",{class:T(["log-col col-time",`col-time-${e.channelType}`])},g(a.time),3)],64))],10,ba))),128))],512)])])])):d("",!0)])),vl.value?(u(),i("div",{key:1,class:T(["locked-overlay",`locked-${e.channelType}`])},[r("div",Pa,[r("div",ja,[p(y(ue),{size:48},{default:h(()=>[p(y(W))]),_:1})]),l[29]||(l[29]=r("h3",{class:"locked-title"},"该渠道已锁定",-1)),p(y(pe),{depth:"3",class:"locked-hint"},{default:h(()=>[...l[28]||(l[28]=[f(" 点击上方按钮解锁以查看内容 ",-1)])]),_:1})])],2)):d("",!0),!1!==Ha.value.supportsSessions?(u(),v(I,{key:2,visible:ul.value,"onUpdate:visible":l[1]||(l[1]=e=>ul.value=e),channel:e.channelType},null,8,["visible","channel"])):d("",!0)]);var s,c}}},[["__scopeId","data-v-6009b6d9"]]),Ia={class:"dashboard-container"},Oa="dashboardChannelOrder",Ea=P({__name:"Home",setup(l){const{uiConfig:n,updateConfig:s,loadUIConfig:o}=Te();function r(e){try{localStorage.setItem(Oa,JSON.stringify(e))}catch(a){}}function d(e,a=n.value.customCliPlatforms){const l=K(e,a);return m.value=l.map(e=>({type:e})),r(l),l}const m=a(function(){try{const e=localStorage.getItem(Oa);if(e){const a=JSON.parse(e);return K(a,n.value.customCliPlatforms)}}catch(e){}return q}().map(e=>({type:e})));async function g(){const e=K(m.value.map(e=>e.type),n.value.customCliPlatforms);m.value=e.map(e=>({type:e})),r(e),await s("homeCliColumns",e),await s("dashboardChannelOrder",e)}function f(e){const a=(null==e?void 0:e.detail)||{};d(a.homeCliColumns,a.customCliPlatforms)}return c(async()=>{window.addEventListener("home-cli-columns-change",f),await o(),d(n.value.homeCliColumns||n.value.dashboardChannelOrder,n.value.customCliPlatforms)}),t(()=>{window.removeEventListener("home-cli-columns-change",f)}),(a,l)=>(u(),i("div",Ia,[p(y(e),{modelValue:m.value,"onUpdate:modelValue":l[0]||(l[0]=e=>m.value=e),class:"dashboard-grid","item-key":"type",animation:200,handle:".drag-handle",onEnd:g},{item:h(({element:e})=>[(u(),v(Ma,{"channel-type":e.type,key:e.type},null,8,["channel-type"]))]),_:1},8,["modelValue"])]))}},[["__scopeId","data-v-276ca51b"]]);export{Ea as default};