coding-tool-x 3.6.12 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -33
- package/dist/web/assets/{Analytics-BuBlsbcI.js → Analytics-Dma_j2Rq.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-DQczxuOX.js → ConfigTemplates-C49Y1PLH.js} +1 -1
- package/dist/web/assets/Home-DGGC8H4g.js +1 -0
- package/dist/web/assets/Home-ewgeIhF7.css +1 -0
- package/dist/web/assets/{PluginManager-C8gAlaps.js → PluginManager-B1ECTHyY.js} +1 -1
- package/dist/web/assets/{ProjectList-DL4JK6ci.css → ProjectList-B_L55-l9.css} +1 -1
- package/dist/web/assets/ProjectList-DyiGyT-H.js +1 -0
- package/dist/web/assets/SessionList-CH5GwwiJ.js +1 -0
- package/dist/web/assets/{SkillManager-BDbNbNkK.js → SkillManager-CRyVhjYQ.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-DGGaGW2c.js → WorkspaceManager-CO9tclVt.js} +1 -1
- package/dist/web/assets/{icons-QFXzEgqM.js → icons-Dop5j7Bf.js} +1 -1
- package/dist/web/assets/index-CM26UrnJ.css +1 -0
- package/dist/web/assets/index-EQq56pRa.js +2 -0
- package/dist/web/assets/{naive-ui-kcWDeJwl.js → naive-ui-CVyvdmg1.js} +1 -1
- package/dist/web/index.html +4 -4
- package/package.json +2 -1
- package/src/commands/channels.js +85 -24
- package/src/commands/daemon.js +7 -4
- package/src/commands/doctor.js +17 -8
- package/src/commands/logs.js +48 -6
- package/src/commands/port-config.js +81 -75
- package/src/commands/proxy-control.js +52 -19
- package/src/commands/stats.js +37 -19
- package/src/commands/toggle-proxy.js +131 -53
- package/src/commands/ui.js +3 -4
- package/src/config/default.js +14 -3
- package/src/config/paths.js +99 -11
- package/src/index.js +11 -16
- package/src/server/api/commands.js +1 -1
- package/src/server/api/config-export.js +4 -2
- package/src/server/api/config-registry.js +40 -34
- package/src/server/api/config.js +2 -1
- package/src/server/api/dashboard.js +22 -6
- package/src/server/api/mcp.js +5 -3
- package/src/server/api/pi-channels.js +349 -0
- package/src/server/api/pi-config.js +164 -0
- package/src/server/api/pi-projects.js +76 -0
- package/src/server/api/pi-proxy.js +154 -0
- package/src/server/api/pi-sessions.js +334 -0
- package/src/server/api/pi-statistics.js +40 -0
- package/src/server/api/plugins.js +1 -1
- package/src/server/api/prompts.js +3 -2
- package/src/server/api/skills.js +1 -1
- package/src/server/api/workspaces.js +2 -2
- package/src/server/index.js +41 -0
- package/src/server/pi-proxy-server.js +66 -0
- package/src/server/services/agents-service.js +2 -1
- package/src/server/services/base/proxy-utils.js +1 -0
- package/src/server/services/channel-balance.js +151 -1
- package/src/server/services/channel-scheduler.js +7 -1
- package/src/server/services/commands-service.js +11 -2
- package/src/server/services/config-export-service.js +275 -18
- package/src/server/services/config-registry-service.js +20 -18
- package/src/server/services/config-sync-manager.js +115 -6
- package/src/server/services/config-sync-service.js +4 -2
- package/src/server/services/config-templates-service.js +183 -45
- package/src/server/services/mcp-service.js +217 -33
- package/src/server/services/pi-auth-providers.js +294 -0
- package/src/server/services/pi-channels.js +94 -0
- package/src/server/services/pi-config.js +287 -0
- package/src/server/services/pi-sessions.js +490 -0
- package/src/server/services/pi-settings-manager.js +571 -0
- package/src/server/services/pi-statistics-service.js +317 -0
- package/src/server/services/plugins-service.js +673 -11
- package/src/server/services/prompts-service.js +112 -7
- package/src/server/services/proxy-log-helper.js +1 -0
- package/src/server/services/proxy-runtime.js +5 -1
- package/src/server/services/skill-service.js +13 -3
- package/src/server/services/speed-test.js +9 -3
- package/src/server/services/ui-config.js +50 -12
- package/src/server/services/workspace-service.js +19 -5
- package/src/server/websocket-server.js +7 -1
- package/dist/web/assets/Home-BvAzzWnB.js +0 -1
- package/dist/web/assets/Home-CIua-b-o.css +0 -1
- package/dist/web/assets/ProjectList-nqgi6_cR.js +0 -1
- package/dist/web/assets/SessionList-D8AxMYy6.js +0 -1
- package/dist/web/assets/index-Dsh4Q5Cg.css +0 -1
- package/dist/web/assets/index-y-eEayxR.js +0 -2
- package/src/utils/cli-flags.js +0 -7
package/src/commands/ui.js
CHANGED
|
@@ -3,14 +3,13 @@ const { startServer } = require('../server');
|
|
|
3
3
|
const open = require('open');
|
|
4
4
|
const { getProxyStatus } = require('../server/proxy-server');
|
|
5
5
|
const { loadConfig } = require('../config/loader');
|
|
6
|
-
const { hasHostFlag } = require('../utils/cli-flags');
|
|
7
6
|
|
|
8
7
|
async function handleUI() {
|
|
9
8
|
// 检查是否为 daemon 模式(PM2 启动)
|
|
10
9
|
const isDaemon = process.argv.includes('--daemon');
|
|
11
10
|
|
|
12
|
-
// 检查是否启用 LAN 访问 (--host
|
|
13
|
-
const enableHost =
|
|
11
|
+
// 检查是否启用 LAN 访问 (--host 标志)
|
|
12
|
+
const enableHost = process.argv.includes('--host');
|
|
14
13
|
const enableHttps = process.argv.includes('--https');
|
|
15
14
|
const host = enableHost ? '0.0.0.0' : '127.0.0.1';
|
|
16
15
|
const protocol = enableHttps ? 'https' : 'http';
|
|
@@ -19,7 +18,7 @@ async function handleUI() {
|
|
|
19
18
|
console.clear();
|
|
20
19
|
console.log(chalk.cyan.bold('\n[NET] 启动 Coding-Tool Web UI...\n'));
|
|
21
20
|
if (enableHost) {
|
|
22
|
-
console.log(chalk.yellow('[WARN] LAN 访问已启用 (--host
|
|
21
|
+
console.log(chalk.yellow('[WARN] LAN 访问已启用 (--host)\n'));
|
|
23
22
|
}
|
|
24
23
|
if (enableHttps) {
|
|
25
24
|
console.log(chalk.yellow('[LOCK] 已启用本地 HTTPS 模式 (--https)\n'));
|
package/src/config/default.js
CHANGED
|
@@ -5,19 +5,23 @@ const { resolvePreferredHomeDir } = require('../utils/home-dir');
|
|
|
5
5
|
const modelMetadataConfig = require('./model-metadata.json');
|
|
6
6
|
|
|
7
7
|
const HOME_DIR = resolvePreferredHomeDir(process.platform, process.env, os.homedir());
|
|
8
|
+
const CLAUDE_CONFIG_DIR = (typeof process.env.CLAUDE_CONFIG_DIR === 'string' && process.env.CLAUDE_CONFIG_DIR.trim())
|
|
9
|
+
? process.env.CLAUDE_CONFIG_DIR.trim()
|
|
10
|
+
: path.join(HOME_DIR, '.claude');
|
|
8
11
|
|
|
9
12
|
const DEFAULT_CONFIG = {
|
|
10
|
-
projectsDir: path.join(
|
|
13
|
+
projectsDir: path.join(CLAUDE_CONFIG_DIR, 'projects'),
|
|
11
14
|
defaultProject: null,
|
|
12
15
|
maxDisplaySessions: 100,
|
|
13
16
|
pageSize: 15,
|
|
14
|
-
currentCliType: 'claude', // 当前CLI工具类型: claude, codex, gemini, opencode
|
|
17
|
+
currentCliType: 'claude', // 当前CLI工具类型: claude, codex, gemini, opencode, pi
|
|
15
18
|
ports: {
|
|
16
19
|
webUI: 19999, // Web UI 页面端口 (同时用于 WebSocket)
|
|
17
20
|
proxy: 20088, // Claude 代理服务端口
|
|
18
21
|
codexProxy: 20089, // Codex 代理服务端口
|
|
19
22
|
geminiProxy: 20090, // Gemini 代理服务端口
|
|
20
|
-
opencodeProxy: 20091
|
|
23
|
+
opencodeProxy: 20091, // OpenCode 代理服务端口
|
|
24
|
+
piProxy: 20092 // OMP 托管 provider 状态端口占位
|
|
21
25
|
},
|
|
22
26
|
maxLogs: 100,
|
|
23
27
|
statsInterval: 30,
|
|
@@ -68,6 +72,13 @@ const DEFAULT_CONFIG = {
|
|
|
68
72
|
output: 15,
|
|
69
73
|
cacheRead: 0.25,
|
|
70
74
|
models: {}
|
|
75
|
+
},
|
|
76
|
+
pi: {
|
|
77
|
+
mode: 'auto',
|
|
78
|
+
input: 2.5,
|
|
79
|
+
output: 15,
|
|
80
|
+
cacheRead: 0.25,
|
|
81
|
+
models: {}
|
|
71
82
|
}
|
|
72
83
|
}
|
|
73
84
|
};
|
package/src/config/paths.js
CHANGED
|
@@ -392,6 +392,8 @@ const PATHS = {
|
|
|
392
392
|
forkRelations: path.join(CONFIG_DIR, 'fork-relations.json'),
|
|
393
393
|
opencodeProjectOrder: path.join(CONFIG_DIR, 'opencode-project-order.json'),
|
|
394
394
|
opencodeSessionOrder: path.join(CONFIG_DIR, 'opencode-session-order.json'),
|
|
395
|
+
piProjectOrder: path.join(CONFIG_DIR, 'pi-project-order.json'),
|
|
396
|
+
piSessionOrder: path.join(CONFIG_DIR, 'pi-session-order.json'),
|
|
395
397
|
|
|
396
398
|
// 渠道配置
|
|
397
399
|
channelsDir: CHANNELS_DIR,
|
|
@@ -399,14 +401,16 @@ const PATHS = {
|
|
|
399
401
|
claude: path.join(CHANNELS_DIR, 'claude.json'),
|
|
400
402
|
codex: path.join(CHANNELS_DIR, 'codex.json'),
|
|
401
403
|
gemini: path.join(CHANNELS_DIR, 'gemini.json'),
|
|
402
|
-
opencode: path.join(CHANNELS_DIR, 'opencode.json')
|
|
404
|
+
opencode: path.join(CHANNELS_DIR, 'opencode.json'),
|
|
405
|
+
pi: path.join(CHANNELS_DIR, 'pi.json')
|
|
403
406
|
},
|
|
404
407
|
activeChannelDir: ACTIVE_CHANNELS_DIR,
|
|
405
408
|
activeChannel: {
|
|
406
409
|
claude: path.join(ACTIVE_CHANNELS_DIR, 'claude.json'),
|
|
407
410
|
codex: path.join(ACTIVE_CHANNELS_DIR, 'codex.json'),
|
|
408
411
|
gemini: path.join(ACTIVE_CHANNELS_DIR, 'gemini.json'),
|
|
409
|
-
opencode: path.join(ACTIVE_CHANNELS_DIR, 'opencode.json')
|
|
412
|
+
opencode: path.join(ACTIVE_CHANNELS_DIR, 'opencode.json'),
|
|
413
|
+
pi: path.join(ACTIVE_CHANNELS_DIR, 'pi.json')
|
|
410
414
|
},
|
|
411
415
|
|
|
412
416
|
// 统计与日志快照
|
|
@@ -437,7 +441,8 @@ const PATHS = {
|
|
|
437
441
|
claude: path.join(RUNTIME_DIR, 'claude-proxy.json'),
|
|
438
442
|
codex: path.join(RUNTIME_DIR, 'codex-proxy.json'),
|
|
439
443
|
gemini: path.join(RUNTIME_DIR, 'gemini-proxy.json'),
|
|
440
|
-
opencode: path.join(RUNTIME_DIR, 'opencode-proxy.json')
|
|
444
|
+
opencode: path.join(RUNTIME_DIR, 'opencode-proxy.json'),
|
|
445
|
+
pi: path.join(RUNTIME_DIR, 'pi-proxy.json')
|
|
441
446
|
},
|
|
442
447
|
|
|
443
448
|
// 请求记录
|
|
@@ -445,7 +450,8 @@ const PATHS = {
|
|
|
445
450
|
claude: path.join(REQUESTS_DIR, 'claude.jsonl'),
|
|
446
451
|
codex: path.join(REQUESTS_DIR, 'codex.jsonl'),
|
|
447
452
|
gemini: path.join(REQUESTS_DIR, 'gemini.jsonl'),
|
|
448
|
-
opencode: path.join(REQUESTS_DIR, 'opencode.jsonl')
|
|
453
|
+
opencode: path.join(REQUESTS_DIR, 'opencode.jsonl'),
|
|
454
|
+
pi: path.join(REQUESTS_DIR, 'pi.jsonl')
|
|
449
455
|
},
|
|
450
456
|
claudeRequestTemplate: path.join(REQUESTS_DIR, 'claude-request-template.json'),
|
|
451
457
|
|
|
@@ -457,35 +463,40 @@ const PATHS = {
|
|
|
457
463
|
claude: path.join(LOCAL_SKILLS_DIR, 'claude'),
|
|
458
464
|
codex: path.join(LOCAL_SKILLS_DIR, 'codex'),
|
|
459
465
|
gemini: path.join(LOCAL_SKILLS_DIR, 'gemini'),
|
|
460
|
-
opencode: path.join(LOCAL_SKILLS_DIR, 'opencode')
|
|
466
|
+
opencode: path.join(LOCAL_SKILLS_DIR, 'opencode'),
|
|
467
|
+
pi: path.join(LOCAL_SKILLS_DIR, 'pi')
|
|
461
468
|
},
|
|
462
469
|
skillRepos: {
|
|
463
470
|
claude: path.join(REPOS_SKILLS_DIR, 'claude.json'),
|
|
464
471
|
codex: path.join(REPOS_SKILLS_DIR, 'codex.json'),
|
|
465
472
|
gemini: path.join(REPOS_SKILLS_DIR, 'gemini.json'),
|
|
466
|
-
opencode: path.join(REPOS_SKILLS_DIR, 'opencode.json')
|
|
473
|
+
opencode: path.join(REPOS_SKILLS_DIR, 'opencode.json'),
|
|
474
|
+
pi: path.join(REPOS_SKILLS_DIR, 'pi.json')
|
|
467
475
|
},
|
|
468
476
|
skillCaches: {
|
|
469
477
|
claude: path.join(CACHE_SKILLS_DIR, 'claude.json'),
|
|
470
478
|
codex: path.join(CACHE_SKILLS_DIR, 'codex.json'),
|
|
471
479
|
gemini: path.join(CACHE_SKILLS_DIR, 'gemini.json'),
|
|
472
|
-
opencode: path.join(CACHE_SKILLS_DIR, 'opencode.json')
|
|
480
|
+
opencode: path.join(CACHE_SKILLS_DIR, 'opencode.json'),
|
|
481
|
+
pi: path.join(CACHE_SKILLS_DIR, 'pi.json')
|
|
473
482
|
},
|
|
474
483
|
pluginRepos: {
|
|
475
484
|
claude: path.join(REPOS_PLUGINS_DIR, 'claude.json'),
|
|
476
485
|
codex: path.join(REPOS_PLUGINS_DIR, 'codex.json'),
|
|
477
486
|
gemini: path.join(REPOS_PLUGINS_DIR, 'gemini.json'),
|
|
478
|
-
opencode: path.join(REPOS_PLUGINS_DIR, 'opencode.json')
|
|
487
|
+
opencode: path.join(REPOS_PLUGINS_DIR, 'opencode.json'),
|
|
488
|
+
pi: path.join(REPOS_PLUGINS_DIR, 'pi.json')
|
|
479
489
|
},
|
|
480
490
|
pluginMarketCache: {
|
|
481
491
|
claude: path.join(CACHE_PLUGINS_DIR, 'claude-market.json'),
|
|
482
492
|
codex: path.join(CACHE_PLUGINS_DIR, 'codex-market.json'),
|
|
483
493
|
gemini: path.join(CACHE_PLUGINS_DIR, 'gemini-market.json'),
|
|
484
|
-
opencode: path.join(CACHE_PLUGINS_DIR, 'opencode-market.json')
|
|
494
|
+
opencode: path.join(CACHE_PLUGINS_DIR, 'opencode-market.json'),
|
|
495
|
+
pi: path.join(CACHE_PLUGINS_DIR, 'pi-market.json')
|
|
485
496
|
},
|
|
486
497
|
|
|
487
498
|
// 原生路径兼容
|
|
488
|
-
skills: path.join(
|
|
499
|
+
skills: path.join(getClaudeConfigDir(), 'skills'),
|
|
489
500
|
|
|
490
501
|
// 旧版本遗留文件搬迁目标
|
|
491
502
|
legacy: {
|
|
@@ -521,16 +532,20 @@ const LEGACY_STORAGE_RELOCATIONS = [
|
|
|
521
532
|
{ source: rootEntry('fork-relations.json'), target: PATHS.forkRelations },
|
|
522
533
|
{ source: rootEntry('opencode-project-order.json'), target: PATHS.opencodeProjectOrder },
|
|
523
534
|
{ source: rootEntry('opencode-session-order.json'), target: PATHS.opencodeSessionOrder },
|
|
535
|
+
{ source: rootEntry('pi-project-order.json'), target: PATHS.piProjectOrder },
|
|
536
|
+
{ source: rootEntry('pi-session-order.json'), target: PATHS.piSessionOrder },
|
|
524
537
|
|
|
525
538
|
// 渠道相关
|
|
526
539
|
{ source: rootEntry('channels.json'), target: PATHS.channels.claude },
|
|
527
540
|
{ source: rootEntry('codex-channels.json'), target: PATHS.channels.codex },
|
|
528
541
|
{ source: rootEntry('gemini-channels.json'), target: PATHS.channels.gemini },
|
|
529
542
|
{ source: rootEntry('opencode-channels.json'), target: PATHS.channels.opencode },
|
|
543
|
+
{ source: rootEntry('pi-channels.json'), target: PATHS.channels.pi },
|
|
530
544
|
{ source: rootEntry('active-channel.json'), target: PATHS.activeChannel.claude },
|
|
531
545
|
{ source: rootEntry('codex-active-channel.json'), target: PATHS.activeChannel.codex },
|
|
532
546
|
{ source: rootEntry('gemini-active-channel.json'), target: PATHS.activeChannel.gemini },
|
|
533
547
|
{ source: rootEntry('opencode-active-channel.json'), target: PATHS.activeChannel.opencode },
|
|
548
|
+
{ source: rootEntry('pi-active-channel.json'), target: PATHS.activeChannel.pi },
|
|
534
549
|
|
|
535
550
|
// 统计与日志
|
|
536
551
|
{ source: rootEntry('statistics.json'), target: PATHS.statistics.summary },
|
|
@@ -553,12 +568,14 @@ const LEGACY_STORAGE_RELOCATIONS = [
|
|
|
553
568
|
{ source: rootEntry('codex-proxy-runtime.json'), target: PATHS.proxyRuntime.codex },
|
|
554
569
|
{ source: rootEntry('gemini-proxy-runtime.json'), target: PATHS.proxyRuntime.gemini },
|
|
555
570
|
{ source: rootEntry('opencode-proxy-runtime.json'), target: PATHS.proxyRuntime.opencode },
|
|
571
|
+
{ source: rootEntry('pi-proxy-runtime.json'), target: PATHS.proxyRuntime.pi },
|
|
556
572
|
{ source: rootEntry('notify-hook.js'), target: PATHS.notifyHook },
|
|
557
573
|
{ source: rootEntry('claude-request-template.json'), target: PATHS.claudeRequestTemplate },
|
|
558
574
|
{ source: rootEntry('claude-requests.jsonl'), target: PATHS.requestSnapshots.claude },
|
|
559
575
|
{ source: rootEntry('codex-requests.jsonl'), target: PATHS.requestSnapshots.codex },
|
|
560
576
|
{ source: rootEntry('gemini-requests.jsonl'), target: PATHS.requestSnapshots.gemini },
|
|
561
577
|
{ source: rootEntry('opencode-requests.jsonl'), target: PATHS.requestSnapshots.opencode },
|
|
578
|
+
{ source: rootEntry('pi-requests.jsonl'), target: PATHS.requestSnapshots.pi },
|
|
562
579
|
|
|
563
580
|
// 备份
|
|
564
581
|
{ source: rootEntry('env-backups'), target: PATHS.envBackups },
|
|
@@ -568,24 +585,29 @@ const LEGACY_STORAGE_RELOCATIONS = [
|
|
|
568
585
|
{ source: rootEntry('codex-skills'), target: PATHS.localSkills.codex },
|
|
569
586
|
{ source: rootEntry('gemini-skills'), target: PATHS.localSkills.gemini },
|
|
570
587
|
{ source: rootEntry('opencode-skills'), target: PATHS.localSkills.opencode },
|
|
588
|
+
{ source: rootEntry('pi-skills'), target: PATHS.localSkills.pi },
|
|
571
589
|
{ source: rootEntry('skill-repos.json'), target: PATHS.skillRepos.claude },
|
|
572
590
|
{ source: rootEntry('codex-skill-repos.json'), target: PATHS.skillRepos.codex },
|
|
573
591
|
{ source: rootEntry('gemini-skill-repos.json'), target: PATHS.skillRepos.gemini },
|
|
574
592
|
{ source: rootEntry('opencode-skill-repos.json'), target: PATHS.skillRepos.opencode },
|
|
593
|
+
{ source: rootEntry('pi-skill-repos.json'), target: PATHS.skillRepos.pi },
|
|
575
594
|
{ source: rootEntry('skills-cache.json'), target: PATHS.skillCaches.claude },
|
|
576
595
|
{ source: rootEntry('codex-skills-cache.json'), target: PATHS.skillCaches.codex },
|
|
577
596
|
{ source: rootEntry('gemini-skills-cache.json'), target: PATHS.skillCaches.gemini },
|
|
578
597
|
{ source: rootEntry('opencode-skills-cache.json'), target: PATHS.skillCaches.opencode },
|
|
598
|
+
{ source: rootEntry('pi-skills-cache.json'), target: PATHS.skillCaches.pi },
|
|
579
599
|
|
|
580
600
|
// 插件仓库缓存
|
|
581
601
|
{ source: rootEntry('plugin-repos.json'), target: PATHS.pluginRepos.claude },
|
|
582
602
|
{ source: rootEntry('codex-plugin-repos.json'), target: PATHS.pluginRepos.codex },
|
|
583
603
|
{ source: rootEntry('gemini-plugin-repos.json'), target: PATHS.pluginRepos.gemini },
|
|
584
604
|
{ source: rootEntry('opencode-plugin-repos.json'), target: PATHS.pluginRepos.opencode },
|
|
605
|
+
{ source: rootEntry('pi-plugin-repos.json'), target: PATHS.pluginRepos.pi },
|
|
585
606
|
{ source: rootEntry('plugins-market-cache.json'), target: PATHS.pluginMarketCache.claude },
|
|
586
607
|
{ source: rootEntry('codex-plugins-market-cache.json'), target: PATHS.pluginMarketCache.codex },
|
|
587
608
|
{ source: rootEntry('gemini-plugins-market-cache.json'), target: PATHS.pluginMarketCache.gemini },
|
|
588
609
|
{ source: rootEntry('opencode-plugins-market-cache.json'), target: PATHS.pluginMarketCache.opencode },
|
|
610
|
+
{ source: rootEntry('pi-plugins-market-cache.json'), target: PATHS.pluginMarketCache.pi },
|
|
589
611
|
|
|
590
612
|
// 已废弃但需要保留的数据
|
|
591
613
|
{ source: rootEntry('oauth-tokens.json'), target: PATHS.legacy.oauthTokens }
|
|
@@ -708,6 +730,16 @@ function resolveExistingEnvPath(envValue) {
|
|
|
708
730
|
return trimmed || '';
|
|
709
731
|
}
|
|
710
732
|
|
|
733
|
+
function expandHomePath(input = '') {
|
|
734
|
+
if (input === '~') {
|
|
735
|
+
return HOME_DIR;
|
|
736
|
+
}
|
|
737
|
+
if (input.startsWith('~/') || input.startsWith('~\\')) {
|
|
738
|
+
return path.join(HOME_DIR, input.slice(2));
|
|
739
|
+
}
|
|
740
|
+
return input;
|
|
741
|
+
}
|
|
742
|
+
|
|
711
743
|
function pickExistingDir(candidates, fallback) {
|
|
712
744
|
for (const candidate of candidates) {
|
|
713
745
|
if (candidate && fs.existsSync(candidate)) {
|
|
@@ -765,6 +797,34 @@ function getOpenCodeConfigDir() {
|
|
|
765
797
|
return preferredDir;
|
|
766
798
|
}
|
|
767
799
|
|
|
800
|
+
function normalizeOmpProfileName(profile = '') {
|
|
801
|
+
const value = String(profile || '').trim();
|
|
802
|
+
return value && value !== 'default' ? value : '';
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
function getOmpProfileName() {
|
|
806
|
+
if (process.env.OMP_PROFILE !== undefined) {
|
|
807
|
+
return normalizeOmpProfileName(process.env.OMP_PROFILE);
|
|
808
|
+
}
|
|
809
|
+
return normalizeOmpProfileName(process.env.PI_PROFILE);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
function getOmpConfigRoot() {
|
|
813
|
+
return expandHomePath(resolveExistingEnvPath(process.env.PI_CONFIG_DIR) || path.join(HOME_DIR, '.omp'));
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
function getPiAgentDir() {
|
|
817
|
+
const configuredDir = resolveExistingEnvPath(process.env.PI_CODING_AGENT_DIR);
|
|
818
|
+
if (configuredDir) {
|
|
819
|
+
return path.resolve(expandHomePath(configuredDir));
|
|
820
|
+
}
|
|
821
|
+
const profile = getOmpProfileName();
|
|
822
|
+
const agentDir = profile
|
|
823
|
+
? path.join(getOmpConfigRoot(), 'profiles', profile, 'agent')
|
|
824
|
+
: path.join(getOmpConfigRoot(), 'agent');
|
|
825
|
+
return path.resolve(agentDir);
|
|
826
|
+
}
|
|
827
|
+
|
|
768
828
|
// 工具特定的原生配置路径(不改变)
|
|
769
829
|
const NATIVE_PATHS = {
|
|
770
830
|
// Claude Code 原生配置
|
|
@@ -772,7 +832,13 @@ const NATIVE_PATHS = {
|
|
|
772
832
|
dir: getClaudeConfigDir(),
|
|
773
833
|
settings: path.join(getClaudeConfigDir(), 'settings.json'),
|
|
774
834
|
settingsBackup: path.join(getClaudeConfigDir(), 'settings.json.cc-tool-backup'),
|
|
835
|
+
prompt: path.join(getClaudeConfigDir(), 'CLAUDE.md'),
|
|
775
836
|
projects: path.join(getClaudeConfigDir(), 'projects'),
|
|
837
|
+
skills: path.join(getClaudeConfigDir(), 'skills'),
|
|
838
|
+
commands: path.join(getClaudeConfigDir(), 'commands'),
|
|
839
|
+
agents: path.join(getClaudeConfigDir(), 'agents'),
|
|
840
|
+
plugins: path.join(getClaudeConfigDir(), 'plugins'),
|
|
841
|
+
mcp: path.join(HOME_DIR, '.claude.json'),
|
|
776
842
|
credentials: path.join(getClaudeConfigDir(), '.credentials.json')
|
|
777
843
|
},
|
|
778
844
|
|
|
@@ -808,6 +874,27 @@ const NATIVE_PATHS = {
|
|
|
808
874
|
messages: path.join(getOpenCodeDataDir(), 'storage', 'message'),
|
|
809
875
|
log: path.join(getOpenCodeDataDir(), 'log'),
|
|
810
876
|
auth: path.join(getOpenCodeDataDir(), 'auth.json')
|
|
877
|
+
},
|
|
878
|
+
|
|
879
|
+
// OMP 原生配置。外部仍使用 pi 渠道键,内部默认落到 OMP 配置目录。
|
|
880
|
+
pi: {
|
|
881
|
+
dir: getPiAgentDir(),
|
|
882
|
+
config: path.join(getPiAgentDir(), 'config.yml'),
|
|
883
|
+
settings: path.join(getPiAgentDir(), 'config.yml'),
|
|
884
|
+
settingsJsonLegacy: path.join(getPiAgentDir(), 'settings.json'),
|
|
885
|
+
auth: path.join(getPiAgentDir(), 'auth.json'),
|
|
886
|
+
models: path.join(getPiAgentDir(), 'models.yml'),
|
|
887
|
+
modelsYml: path.join(getPiAgentDir(), 'models.yml'),
|
|
888
|
+
modelsJsonLegacy: path.join(getPiAgentDir(), 'models.json'),
|
|
889
|
+
mcp: path.join(getPiAgentDir(), 'mcp.json'),
|
|
890
|
+
sessions: path.join(getPiAgentDir(), 'sessions'),
|
|
891
|
+
skills: path.join(getPiAgentDir(), 'skills'),
|
|
892
|
+
prompts: path.join(getPiAgentDir(), 'prompts'),
|
|
893
|
+
commands: path.join(getPiAgentDir(), 'commands'),
|
|
894
|
+
notes: path.join(getPiAgentDir(), 'notes'),
|
|
895
|
+
extensions: path.join(getPiAgentDir(), 'extensions'),
|
|
896
|
+
themes: path.join(getPiAgentDir(), 'themes'),
|
|
897
|
+
packages: path.join(getPiAgentDir(), 'packages')
|
|
811
898
|
}
|
|
812
899
|
};
|
|
813
900
|
|
|
@@ -827,5 +914,6 @@ module.exports = {
|
|
|
827
914
|
getCodexDir,
|
|
828
915
|
getGeminiDir,
|
|
829
916
|
getOpenCodeDataDir,
|
|
830
|
-
getOpenCodeConfigDir
|
|
917
|
+
getOpenCodeConfigDir,
|
|
918
|
+
getPiAgentDir
|
|
831
919
|
};
|
package/src/index.js
CHANGED
|
@@ -14,9 +14,9 @@ const { handleStats, handleStatsExport } = require('./commands/stats');
|
|
|
14
14
|
const { handleDoctor } = require('./commands/doctor');
|
|
15
15
|
const { handleUpdate } = require('./commands/update');
|
|
16
16
|
const { ensureStorageDirMigrated } = require('./config/paths');
|
|
17
|
+
const { normalizePlatformKey } = require('./shared/platforms');
|
|
17
18
|
const PluginManager = require('./plugins/plugin-manager');
|
|
18
19
|
const eventBus = require('./plugins/event-bus');
|
|
19
|
-
const { hasHostFlag } = require('./utils/cli-flags');
|
|
20
20
|
const chalk = require('chalk');
|
|
21
21
|
const path = require('path');
|
|
22
22
|
const fs = require('fs');
|
|
@@ -54,12 +54,9 @@ function showHelp() {
|
|
|
54
54
|
console.log(' ctx ui 前台启动 Web UI(仅本地访问)');
|
|
55
55
|
console.log(' ctx ui --https 前台启动 Web UI(本地 HTTPS)');
|
|
56
56
|
console.log(' ctx ui --host 前台启动 Web UI(允许 LAN 访问)');
|
|
57
|
-
console.log(' ctx ui --hosts 前台启动 Web UI(同 --host)');
|
|
58
|
-
console.log(' ctx --hosts 前台启动 Web UI(同 ctx ui --host)');
|
|
59
57
|
console.log(' ctx ui start 后台启动 Web UI');
|
|
60
58
|
console.log(' ctx ui start --https 后台启动 Web UI(本地 HTTPS)');
|
|
61
59
|
console.log(' ctx ui start --host 后台启动 Web UI(允许 LAN 访问)');
|
|
62
|
-
console.log(' ctx ui start --hosts 后台启动 Web UI(同 --host)');
|
|
63
60
|
console.log(' ctx ui stop 停止 Web UI');
|
|
64
61
|
console.log(' ctx ui restart 重启 Web UI\n');
|
|
65
62
|
|
|
@@ -70,12 +67,15 @@ function showHelp() {
|
|
|
70
67
|
console.log(' ctx codex start 启动 Codex 代理');
|
|
71
68
|
console.log(' ctx gemini start 启动 Gemini 代理');
|
|
72
69
|
console.log(' ctx opencode start 启动 OpenCode 代理');
|
|
73
|
-
console.log(
|
|
70
|
+
console.log(' ctx pi start 启用 OMP 受管模型配置');
|
|
71
|
+
console.log(' ctx omp start ctx pi 的别名,启用 OMP 受管模型配置');
|
|
72
|
+
console.log(chalk.gray(' (codex/gemini/opencode/pi/omp 命令与 claude 类似)\n'));
|
|
74
73
|
|
|
75
74
|
console.log(chalk.yellow('[LOG] 日志管理:'));
|
|
76
75
|
console.log(' ctx logs 查看所有日志');
|
|
77
76
|
console.log(' ctx logs ui 查看 UI 日志');
|
|
78
77
|
console.log(' ctx logs claude 查看 Claude 日志');
|
|
78
|
+
console.log(' ctx logs omp 查看 OMP 相关 UI/server 日志');
|
|
79
79
|
console.log(' ctx logs --lines 100 查看最近 100 行');
|
|
80
80
|
console.log(' ctx logs --follow 实时跟踪日志');
|
|
81
81
|
console.log(' ctx logs --clear 清空日志\n');
|
|
@@ -83,6 +83,7 @@ function showHelp() {
|
|
|
83
83
|
console.log(chalk.yellow('[STATS] 统计信息:'));
|
|
84
84
|
console.log(' ctx stats 查看总体统计');
|
|
85
85
|
console.log(' ctx stats claude 查看 Claude 统计');
|
|
86
|
+
console.log(' ctx stats omp 查看 OMP 统计');
|
|
86
87
|
console.log(' ctx stats --today 查看今日统计');
|
|
87
88
|
console.log(' ctx stats export 导出统计数据\n');
|
|
88
89
|
|
|
@@ -160,13 +161,6 @@ async function main() {
|
|
|
160
161
|
return;
|
|
161
162
|
}
|
|
162
163
|
|
|
163
|
-
// LAN 快捷入口,等同于 ctx ui --host/--hosts
|
|
164
|
-
if (hasHostFlag(process.argv) && !args.some((arg) => arg && !arg.startsWith('-'))) {
|
|
165
|
-
const { handleUI } = require('./commands/ui');
|
|
166
|
-
await handleUI();
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
164
|
// daemon 命令兼容(保持与 README 中旧命令一致)
|
|
171
165
|
if (args[0] === 'daemon') {
|
|
172
166
|
const subCommand = args[1] || 'status';
|
|
@@ -271,10 +265,11 @@ async function main() {
|
|
|
271
265
|
return;
|
|
272
266
|
}
|
|
273
267
|
|
|
274
|
-
// claude/codex/gemini/opencode
|
|
275
|
-
const channels = ['claude', 'codex', 'gemini', 'opencode'];
|
|
276
|
-
|
|
277
|
-
|
|
268
|
+
// claude/codex/gemini/opencode/pi 代理管理命令;omp 是 pi 的输入别名
|
|
269
|
+
const channels = ['claude', 'codex', 'gemini', 'opencode', 'pi'];
|
|
270
|
+
const normalizedChannel = normalizePlatformKey(args[0]);
|
|
271
|
+
if (channels.includes(normalizedChannel)) {
|
|
272
|
+
const channel = String(args[0] || '').trim().toLowerCase();
|
|
278
273
|
const action = args[1] || 'status';
|
|
279
274
|
|
|
280
275
|
switch (action) {
|
|
@@ -9,7 +9,7 @@ const { CommandsService } = require('../services/commands-service');
|
|
|
9
9
|
const { sendApiError } = require('./validation-errors');
|
|
10
10
|
|
|
11
11
|
const router = express.Router();
|
|
12
|
-
const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode'];
|
|
12
|
+
const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode', 'pi'];
|
|
13
13
|
const commandServices = new Map();
|
|
14
14
|
|
|
15
15
|
function resolvePlatform(rawPlatform) {
|
|
@@ -25,7 +25,8 @@ function resolveChannelsByType(exportData) {
|
|
|
25
25
|
claude: Array.isArray(typed.claude) ? typed.claude : (Array.isArray(raw.channels) ? raw.channels : []),
|
|
26
26
|
codex: Array.isArray(typed.codex) ? typed.codex : [],
|
|
27
27
|
gemini: Array.isArray(typed.gemini) ? typed.gemini : [],
|
|
28
|
-
opencode: Array.isArray(typed.opencode) ? typed.opencode : []
|
|
28
|
+
opencode: Array.isArray(typed.opencode) ? typed.opencode : [],
|
|
29
|
+
pi: Array.isArray(typed.pi) ? typed.pi : []
|
|
29
30
|
};
|
|
30
31
|
}
|
|
31
32
|
|
|
@@ -44,7 +45,8 @@ function buildPreviewSummary(data) {
|
|
|
44
45
|
...channelsByType.claude.map(c => ({ ...c, type: c.type || 'claude' })),
|
|
45
46
|
...channelsByType.codex.map(c => ({ ...c, type: c.type || 'codex' })),
|
|
46
47
|
...channelsByType.gemini.map(c => ({ ...c, type: c.type || 'gemini' })),
|
|
47
|
-
...channelsByType.opencode.map(c => ({ ...c, type: c.type || 'opencode' }))
|
|
48
|
+
...channelsByType.opencode.map(c => ({ ...c, type: c.type || 'opencode' })),
|
|
49
|
+
...channelsByType.pi.map(c => ({ ...c, type: c.type || 'pi' }))
|
|
48
50
|
];
|
|
49
51
|
|
|
50
52
|
return {
|
|
@@ -43,6 +43,42 @@ function validatePlatform(platform) {
|
|
|
43
43
|
return null;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
const PLATFORM_SYNC_METHODS = {
|
|
47
|
+
claude: { sync: 'syncToClaude', remove: 'removeFromClaude' },
|
|
48
|
+
codex: { sync: 'syncToCodex', remove: 'removeFromCodex' },
|
|
49
|
+
gemini: { sync: 'syncToGemini', remove: 'removeFromGemini' },
|
|
50
|
+
opencode: { sync: 'syncToOpenCode', remove: 'removeFromOpenCode' },
|
|
51
|
+
pi: { sync: 'syncToPi', remove: 'removeFromPi' }
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
function syncPlatform(type, name, platform) {
|
|
55
|
+
const method = PLATFORM_SYNC_METHODS[platform]?.sync;
|
|
56
|
+
if (method && typeof syncManager[method] === 'function') {
|
|
57
|
+
syncManager[method](type, name);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function removePlatform(type, name, platform) {
|
|
62
|
+
const method = PLATFORM_SYNC_METHODS[platform]?.remove;
|
|
63
|
+
if (method && typeof syncManager[method] === 'function') {
|
|
64
|
+
syncManager[method](type, name);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function syncEnabledPlatforms(type, name, platforms = {}) {
|
|
69
|
+
for (const platform of VALID_PLATFORMS) {
|
|
70
|
+
if (platforms?.[platform]) {
|
|
71
|
+
syncPlatform(type, name, platform);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function removeAllPlatforms(type, name) {
|
|
77
|
+
for (const platform of VALID_PLATFORMS) {
|
|
78
|
+
removePlatform(type, name, platform);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
46
82
|
/**
|
|
47
83
|
* GET /api/config-registry/stats
|
|
48
84
|
* Get statistics for all config types
|
|
@@ -193,24 +229,10 @@ router.put('/:type/:name/toggle', async (req, res) => {
|
|
|
193
229
|
// Apply sync based on new state
|
|
194
230
|
if (enabled) {
|
|
195
231
|
// Sync to platforms where platform=true
|
|
196
|
-
|
|
197
|
-
syncManager.syncToClaude(type, name);
|
|
198
|
-
}
|
|
199
|
-
if (item.platforms?.codex) {
|
|
200
|
-
syncManager.syncToCodex(type, name);
|
|
201
|
-
}
|
|
202
|
-
if (item.platforms?.gemini) {
|
|
203
|
-
syncManager.syncToGemini(type, name);
|
|
204
|
-
}
|
|
205
|
-
if (item.platforms?.opencode) {
|
|
206
|
-
syncManager.syncToOpenCode(type, name);
|
|
207
|
-
}
|
|
232
|
+
syncEnabledPlatforms(type, name, item.platforms);
|
|
208
233
|
} else {
|
|
209
234
|
// Remove from all platforms
|
|
210
|
-
|
|
211
|
-
syncManager.removeFromCodex(type, name);
|
|
212
|
-
syncManager.removeFromGemini(type, name);
|
|
213
|
-
syncManager.removeFromOpenCode(type, name);
|
|
235
|
+
removeAllPlatforms(type, name);
|
|
214
236
|
}
|
|
215
237
|
|
|
216
238
|
res.json({
|
|
@@ -279,26 +301,10 @@ router.put('/:type/:name/platform/:platform', async (req, res) => {
|
|
|
279
301
|
// Apply sync based on new state
|
|
280
302
|
if (enabled && item.enabled) {
|
|
281
303
|
// Sync to this platform (only if item is enabled)
|
|
282
|
-
|
|
283
|
-
syncManager.syncToClaude(type, name);
|
|
284
|
-
} else if (platform === 'codex') {
|
|
285
|
-
syncManager.syncToCodex(type, name);
|
|
286
|
-
} else if (platform === 'gemini') {
|
|
287
|
-
syncManager.syncToGemini(type, name);
|
|
288
|
-
} else if (platform === 'opencode') {
|
|
289
|
-
syncManager.syncToOpenCode(type, name);
|
|
290
|
-
}
|
|
304
|
+
syncPlatform(type, name, platform);
|
|
291
305
|
} else {
|
|
292
306
|
// Remove from this platform
|
|
293
|
-
|
|
294
|
-
syncManager.removeFromClaude(type, name);
|
|
295
|
-
} else if (platform === 'codex') {
|
|
296
|
-
syncManager.removeFromCodex(type, name);
|
|
297
|
-
} else if (platform === 'gemini') {
|
|
298
|
-
syncManager.removeFromGemini(type, name);
|
|
299
|
-
} else if (platform === 'opencode') {
|
|
300
|
-
syncManager.removeFromOpenCode(type, name);
|
|
301
|
-
}
|
|
307
|
+
removePlatform(type, name, platform);
|
|
302
308
|
}
|
|
303
309
|
|
|
304
310
|
res.json({
|
package/src/server/api/config.js
CHANGED
|
@@ -408,7 +408,8 @@ router.get('/advanced', (req, res) => {
|
|
|
408
408
|
proxy: config.ports?.proxy || 20088,
|
|
409
409
|
codexProxy: config.ports?.codexProxy || 20089,
|
|
410
410
|
geminiProxy: config.ports?.geminiProxy || 20090,
|
|
411
|
-
opencodeProxy: config.ports?.opencodeProxy || 20091
|
|
411
|
+
opencodeProxy: config.ports?.opencodeProxy || 20091,
|
|
412
|
+
piProxy: config.ports?.piProxy || 20092
|
|
412
413
|
},
|
|
413
414
|
maxLogs: config.maxLogs || 100,
|
|
414
415
|
statsInterval: config.statsInterval || 30,
|
|
@@ -10,21 +10,25 @@ const { getProxyStatus } = require('../proxy-server');
|
|
|
10
10
|
const { getCodexProxyStatus } = require('../codex-proxy-server');
|
|
11
11
|
const { getGeminiProxyStatus } = require('../gemini-proxy-server');
|
|
12
12
|
const { getOpenCodeProxyStatus } = require('../opencode-proxy-server');
|
|
13
|
+
const { getPiProxyStatus } = require('../pi-proxy-server');
|
|
13
14
|
const { getProjectAndSessionCounts: getClaudeCounts } = require('../services/sessions');
|
|
14
15
|
const { getProjectAndSessionCounts: getCodexCounts } = require('../services/codex-sessions');
|
|
15
16
|
const { getProjectAndSessionCounts: getGeminiCounts } = require('../services/gemini-sessions');
|
|
16
17
|
const { getProjectAndSessionCounts: getOpenCodeCounts } = require('../services/opencode-sessions');
|
|
18
|
+
const { getProjectAndSessionCounts: getPiCounts } = require('../services/pi-sessions');
|
|
17
19
|
|
|
18
20
|
// Channel-specific services
|
|
19
21
|
const { getChannels: getCodexChannels } = require('../services/codex-channels');
|
|
20
22
|
const { getChannels: getGeminiChannels } = require('../services/gemini-channels');
|
|
21
23
|
const { getChannels: getOpenCodeChannels } = require('../services/opencode-channels');
|
|
24
|
+
const { getChannels: getPiChannels } = require('../services/pi-channels');
|
|
22
25
|
|
|
23
26
|
// Statistics
|
|
24
27
|
const { getTodayStatistics: getClaudeTodayStatistics } = require('../services/claude-statistics-service');
|
|
25
28
|
const { getTodayStatistics: getCodexTodayStatistics } = require('../services/codex-statistics-service');
|
|
26
29
|
const { getTodayStatistics: getGeminiTodayStatistics } = require('../services/gemini-statistics-service');
|
|
27
30
|
const { getTodayStatistics: getOpenCodeTodayStatistics } = require('../services/opencode-statistics-service');
|
|
31
|
+
const { getTodayStatistics: getPiTodayStatistics } = require('../services/pi-statistics-service');
|
|
28
32
|
|
|
29
33
|
/**
|
|
30
34
|
* GET /api/dashboard/init
|
|
@@ -42,18 +46,22 @@ router.get('/init', async (req, res) => {
|
|
|
42
46
|
codexChannels,
|
|
43
47
|
geminiChannels,
|
|
44
48
|
opencodeChannels,
|
|
49
|
+
piChannels,
|
|
45
50
|
claudeProxyStatus,
|
|
46
51
|
codexProxyStatus,
|
|
47
52
|
geminiProxyStatus,
|
|
48
53
|
opencodeProxyStatus,
|
|
54
|
+
piProxyStatus,
|
|
49
55
|
claudeTodayStats,
|
|
50
56
|
codexTodayStats,
|
|
51
57
|
geminiTodayStats,
|
|
52
58
|
opencodeTodayStats,
|
|
59
|
+
piTodayStats,
|
|
53
60
|
claudeCounts,
|
|
54
61
|
codexCounts,
|
|
55
62
|
geminiCounts,
|
|
56
|
-
opencodeCounts
|
|
63
|
+
opencodeCounts,
|
|
64
|
+
piCounts
|
|
57
65
|
] = await Promise.all([
|
|
58
66
|
// UI Config
|
|
59
67
|
Promise.resolve(loadUIConfig()),
|
|
@@ -66,24 +74,28 @@ router.get('/init', async (req, res) => {
|
|
|
66
74
|
Promise.resolve(getCodexChannels()),
|
|
67
75
|
Promise.resolve(getGeminiChannels()),
|
|
68
76
|
Promise.resolve(getOpenCodeChannels()),
|
|
77
|
+
Promise.resolve(getPiChannels()),
|
|
69
78
|
|
|
70
79
|
// Proxy Status
|
|
71
80
|
Promise.resolve(getProxyStatus()),
|
|
72
81
|
Promise.resolve(getCodexProxyStatus()),
|
|
73
82
|
Promise.resolve(getGeminiProxyStatus()),
|
|
74
83
|
Promise.resolve(getOpenCodeProxyStatus()),
|
|
84
|
+
Promise.resolve(getPiProxyStatus()),
|
|
75
85
|
|
|
76
86
|
// Today Stats (所有平台)
|
|
77
87
|
Promise.resolve(getClaudeTodayStatistics()),
|
|
78
88
|
Promise.resolve(getCodexTodayStatistics()),
|
|
79
89
|
Promise.resolve(getGeminiTodayStatistics()),
|
|
80
90
|
Promise.resolve(getOpenCodeTodayStatistics()),
|
|
91
|
+
Promise.resolve(getPiTodayStatistics()),
|
|
81
92
|
|
|
82
93
|
// 轻量级统计
|
|
83
94
|
Promise.resolve(getClaudeCounts(config)),
|
|
84
95
|
Promise.resolve(getCodexCounts()),
|
|
85
96
|
Promise.resolve(getGeminiCounts()),
|
|
86
|
-
Promise.resolve(getOpenCodeCounts())
|
|
97
|
+
Promise.resolve(getOpenCodeCounts()),
|
|
98
|
+
Promise.resolve(getPiCounts())
|
|
87
99
|
]);
|
|
88
100
|
|
|
89
101
|
// 格式化统计数据:取 summary 和 byModel 中的数据
|
|
@@ -108,25 +120,29 @@ router.get('/init', async (req, res) => {
|
|
|
108
120
|
claude: claudeChannels,
|
|
109
121
|
codex: codexChannels,
|
|
110
122
|
gemini: geminiChannels,
|
|
111
|
-
opencode: opencodeChannels.channels || []
|
|
123
|
+
opencode: opencodeChannels.channels || [],
|
|
124
|
+
pi: piChannels.channels || []
|
|
112
125
|
},
|
|
113
126
|
proxyStatus: {
|
|
114
127
|
claude: claudeProxyStatus,
|
|
115
128
|
codex: codexProxyStatus,
|
|
116
129
|
gemini: geminiProxyStatus,
|
|
117
|
-
opencode: opencodeProxyStatus
|
|
130
|
+
opencode: opencodeProxyStatus,
|
|
131
|
+
pi: piProxyStatus
|
|
118
132
|
},
|
|
119
133
|
counts: {
|
|
120
134
|
claude: claudeCounts || { projectCount: 0, sessionCount: 0 },
|
|
121
135
|
codex: codexCounts || { projectCount: 0, sessionCount: 0 },
|
|
122
136
|
gemini: geminiCounts || { projectCount: 0, sessionCount: 0 },
|
|
123
|
-
opencode: opencodeCounts || { projectCount: 0, sessionCount: 0 }
|
|
137
|
+
opencode: opencodeCounts || { projectCount: 0, sessionCount: 0 },
|
|
138
|
+
pi: piCounts || { projectCount: 0, sessionCount: 0 }
|
|
124
139
|
},
|
|
125
140
|
todayStats: {
|
|
126
141
|
claude: formatStats(claudeTodayStats),
|
|
127
142
|
codex: formatStats(codexTodayStats),
|
|
128
143
|
gemini: formatStats(geminiTodayStats),
|
|
129
|
-
opencode: formatStats(opencodeTodayStats)
|
|
144
|
+
opencode: formatStats(opencodeTodayStats),
|
|
145
|
+
pi: formatStats(piTodayStats)
|
|
130
146
|
}
|
|
131
147
|
}
|
|
132
148
|
});
|