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
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const { loadConfig } = require('../config/loader');
|
|
2
|
+
const { saveProxyStartTime, clearProxyStartTime, getProxyStartTime, getProxyRuntime } = require('./services/proxy-runtime');
|
|
3
|
+
const { syncManagedOmpProviders, disableManagedOmpProviders, getEnabledChannels } = require('./services/pi-channels');
|
|
4
|
+
|
|
5
|
+
let running = false;
|
|
6
|
+
let currentPort = null;
|
|
7
|
+
let lastSyncResult = null;
|
|
8
|
+
|
|
9
|
+
async function startPiProxyServer(options = {}) {
|
|
10
|
+
const preserveStartTime = options.preserveStartTime || false;
|
|
11
|
+
const config = loadConfig();
|
|
12
|
+
currentPort = config.ports?.piProxy || 20092;
|
|
13
|
+
lastSyncResult = syncManagedOmpProviders();
|
|
14
|
+
running = true;
|
|
15
|
+
saveProxyStartTime('pi', preserveStartTime);
|
|
16
|
+
return {
|
|
17
|
+
success: true,
|
|
18
|
+
port: currentPort,
|
|
19
|
+
sync: lastSyncResult,
|
|
20
|
+
warnings: lastSyncResult?.warnings || []
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function stopPiProxyServer(options = {}) {
|
|
25
|
+
const clearStartTime = options.clearStartTime !== false;
|
|
26
|
+
const stoppedPort = currentPort;
|
|
27
|
+
lastSyncResult = disableManagedOmpProviders();
|
|
28
|
+
running = false;
|
|
29
|
+
currentPort = null;
|
|
30
|
+
if (clearStartTime) {
|
|
31
|
+
clearProxyStartTime('pi');
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
success: true,
|
|
35
|
+
port: stoppedPort,
|
|
36
|
+
sync: lastSyncResult,
|
|
37
|
+
warnings: lastSyncResult?.warnings || []
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getPiProxyStatus() {
|
|
42
|
+
const config = loadConfig();
|
|
43
|
+
const startTime = getProxyStartTime('pi', { allowRecovery: running });
|
|
44
|
+
const runtime = getProxyRuntime('pi', { allowRecovery: running });
|
|
45
|
+
const enabledCount = getEnabledChannels().length;
|
|
46
|
+
const validation = lastSyncResult?.validation || null;
|
|
47
|
+
return {
|
|
48
|
+
running,
|
|
49
|
+
port: currentPort,
|
|
50
|
+
defaultPort: config.ports?.piProxy || 20092,
|
|
51
|
+
startTime,
|
|
52
|
+
runtime,
|
|
53
|
+
mode: 'models-yml-provider-config',
|
|
54
|
+
enabledChannelsCount: enabledCount,
|
|
55
|
+
modelsPath: lastSyncResult?.modelsPath || lastSyncResult?.path || null,
|
|
56
|
+
backupPath: lastSyncResult?.backupPath || null,
|
|
57
|
+
modelsValidation: validation,
|
|
58
|
+
warnings: lastSyncResult?.warnings || []
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = {
|
|
63
|
+
startPiProxyServer,
|
|
64
|
+
stopPiProxyServer,
|
|
65
|
+
getPiProxyStatus
|
|
66
|
+
};
|
|
@@ -26,7 +26,8 @@ const OPENCODE_CONFIG_DIR = NATIVE_PATHS.opencode.config;
|
|
|
26
26
|
const CODEX_CONFIG_PATH = NATIVE_PATHS.codex.config;
|
|
27
27
|
const HOME_DIR = resolvePreferredHomeDir(process.platform, process.env, os.homedir());
|
|
28
28
|
const CODEX_AGENTS_DIR = path.join(path.dirname(CODEX_CONFIG_PATH), 'agents');
|
|
29
|
-
const CLAUDE_AGENTS_DIR =
|
|
29
|
+
const CLAUDE_AGENTS_DIR = NATIVE_PATHS.claude.agents
|
|
30
|
+
|| path.join(NATIVE_PATHS.claude.dir || path.dirname(NATIVE_PATHS.claude.settings), 'agents');
|
|
30
31
|
const GEMINI_AGENTS_DIR = path.join(NATIVE_PATHS.gemini.dir, 'agents');
|
|
31
32
|
const CODEX_CONFIG_MODES = new Set(['none', 'managed', 'custom']);
|
|
32
33
|
|
|
@@ -101,6 +101,7 @@ function normalizeGatewaySourceType(value, fallback = 'claude') {
|
|
|
101
101
|
if (normalized === 'claude') return 'claude';
|
|
102
102
|
if (normalized === 'codex') return 'codex';
|
|
103
103
|
if (normalized === 'gemini') return 'gemini';
|
|
104
|
+
if (normalized === 'opencode') return 'opencode';
|
|
104
105
|
if (normalized === 'openai_compatible') return 'openai_compatible';
|
|
105
106
|
return fallback;
|
|
106
107
|
}
|
|
@@ -12,7 +12,8 @@ const REQUEST_TIMEOUT_MS = 8000;
|
|
|
12
12
|
const MAX_RESPONSE_BYTES = 1024 * 1024;
|
|
13
13
|
const QUOTA_UNIT = 500000;
|
|
14
14
|
const VELOERA_QUOTA_UNIT = 1000000;
|
|
15
|
-
const
|
|
15
|
+
const NEWCLI_QUOTA_UNIT = 1000000;
|
|
16
|
+
const VALID_SOURCES = new Set(['claude', 'codex', 'gemini', 'opencode', 'pi']);
|
|
16
17
|
const GATEWAY_PATH_SEGMENTS = new Set(['openai', 'anthropic', 'claude', 'gemini', 'codex']);
|
|
17
18
|
const HUB_PLATFORMS = new Set(['new-api', 'one-api', 'one-hub', 'done-hub', 'veloera', 'anyrouter', 'aihubmix']);
|
|
18
19
|
const UNSUPPORTED_BALANCE_PLATFORMS = new Set(['dashscope', 'modelscope']);
|
|
@@ -415,6 +416,7 @@ async function tryRequestJson(url, options) {
|
|
|
415
416
|
function detectPlatformByUrlHint(...values) {
|
|
416
417
|
const value = values.map(item => String(item || '')).join(' ').toLowerCase();
|
|
417
418
|
if (value.includes('88code') || value.includes('88-code') || value.includes('rainapp.top')) return '88code';
|
|
419
|
+
if (value.includes('code.newcli.com') || value.includes('newcli') || value.includes('new-cli')) return 'newcli';
|
|
418
420
|
if (value.includes('openrouter.ai') || value.includes('openrouter')) return 'openrouter';
|
|
419
421
|
if (value.includes('aihubmix')) return 'aihubmix';
|
|
420
422
|
if (value.includes('dashscope') || value.includes('dashscope.aliyuncs.com') || value.includes('compatible-mode')) return 'dashscope';
|
|
@@ -600,6 +602,77 @@ function buildSiliconFlowUserInfoSnapshot(payload) {
|
|
|
600
602
|
});
|
|
601
603
|
}
|
|
602
604
|
|
|
605
|
+
function normalizeNewCliQuotaUnit(value) {
|
|
606
|
+
return normalizeQuotaUnit(value, NEWCLI_QUOTA_UNIT);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
function extractNewCliSubscriptionItems(payload) {
|
|
610
|
+
if (!payload || typeof payload !== 'object') return [];
|
|
611
|
+
const data = payload.data && typeof payload.data === 'object' ? payload.data : payload;
|
|
612
|
+
const subscription = data.subscription && typeof data.subscription === 'object' ? data.subscription : data;
|
|
613
|
+
const candidates = [
|
|
614
|
+
subscription.active,
|
|
615
|
+
subscription.subscriptions,
|
|
616
|
+
subscription.items,
|
|
617
|
+
data.subscriptions,
|
|
618
|
+
data.items,
|
|
619
|
+
Array.isArray(subscription) ? subscription : null,
|
|
620
|
+
Array.isArray(data) ? data : null
|
|
621
|
+
];
|
|
622
|
+
for (const candidate of candidates) {
|
|
623
|
+
if (Array.isArray(candidate)) return candidate;
|
|
624
|
+
}
|
|
625
|
+
return [];
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
function shouldUseNewCliSubscription(item = {}) {
|
|
629
|
+
if (!item || typeof item !== 'object') return false;
|
|
630
|
+
if (item.isActive === false) return false;
|
|
631
|
+
const status = String(item.status || item.subscriptionStatus || '').trim().toUpperCase();
|
|
632
|
+
return !status || status === 'ACTIVE' || status === '活跃中';
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function buildNewCliDashboardSnapshot(payload) {
|
|
636
|
+
const items = extractNewCliSubscriptionItems(payload).filter(shouldUseNewCliSubscription);
|
|
637
|
+
if (!items.length) return makeHiddenSnapshot('newcli');
|
|
638
|
+
|
|
639
|
+
const data = payload?.data && typeof payload.data === 'object' ? payload.data : payload;
|
|
640
|
+
const unit = normalizeNewCliQuotaUnit(data?.quotaUnit || data?.quota_unit || data?.quota_per_unit || data?.quotaPerUnit);
|
|
641
|
+
let remainingRaw = 0;
|
|
642
|
+
let usedRaw = 0;
|
|
643
|
+
let totalRaw = 0;
|
|
644
|
+
let hasRemaining = false;
|
|
645
|
+
let hasTotal = false;
|
|
646
|
+
|
|
647
|
+
for (const item of items) {
|
|
648
|
+
const plan = item.plan && typeof item.plan === 'object' ? item.plan : {};
|
|
649
|
+
const remaining = readMoneyField(item, 'quotaRemaining', 'quota_remaining', 'remainingQuota', 'remaining_quota');
|
|
650
|
+
const used = readMoneyField(item, 'quotaUsed', 'quota_used', 'usedQuota', 'used_quota') || 0;
|
|
651
|
+
const limit = readMoneyField(item, 'quotaLimit', 'quota_limit')
|
|
652
|
+
?? readMoneyField(plan, 'quotaLimit', 'quota_limit');
|
|
653
|
+
|
|
654
|
+
if (remaining != null) {
|
|
655
|
+
hasRemaining = true;
|
|
656
|
+
remainingRaw += Math.max(0, remaining);
|
|
657
|
+
usedRaw += Math.max(0, used);
|
|
658
|
+
if (limit != null) {
|
|
659
|
+
hasTotal = true;
|
|
660
|
+
totalRaw += Math.max(0, limit);
|
|
661
|
+
} else {
|
|
662
|
+
totalRaw += Math.max(0, remaining + used);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
if (!hasRemaining) return makeHiddenSnapshot('newcli');
|
|
668
|
+
|
|
669
|
+
return makeVisibleSnapshot('newcli', {
|
|
670
|
+
remaining: remainingRaw / unit,
|
|
671
|
+
used: usedRaw / unit,
|
|
672
|
+
total: (hasTotal || usedRaw > 0) ? totalRaw / unit : undefined
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
|
|
603
676
|
function extractQuotaUnitFromStatus(payload) {
|
|
604
677
|
if (!payload || typeof payload !== 'object') return null;
|
|
605
678
|
const data = payload.data && typeof payload.data === 'object' ? payload.data : payload;
|
|
@@ -791,6 +864,41 @@ function buildSiliconFlowApiBaseCandidates(baseUrl, channel = {}) {
|
|
|
791
864
|
return candidates;
|
|
792
865
|
}
|
|
793
866
|
|
|
867
|
+
function buildNewCliWebBaseCandidates(baseUrl, channel = {}) {
|
|
868
|
+
const candidates = [];
|
|
869
|
+
const inputs = [
|
|
870
|
+
channel.balanceBaseUrl,
|
|
871
|
+
channel.websiteUrl,
|
|
872
|
+
channel.baseUrl,
|
|
873
|
+
baseUrl
|
|
874
|
+
].filter(Boolean);
|
|
875
|
+
|
|
876
|
+
for (const input of inputs) {
|
|
877
|
+
try {
|
|
878
|
+
const parsed = new URL(input);
|
|
879
|
+
addUnique(candidates, parsed.origin);
|
|
880
|
+
} catch {}
|
|
881
|
+
}
|
|
882
|
+
return candidates;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
function buildNewCliAuthHeaderCandidates(token) {
|
|
886
|
+
const raw = stripBearer(token).replace(/^cookie:\s*/i, '').trim();
|
|
887
|
+
if (!raw) return [];
|
|
888
|
+
if (raw.includes('=')) {
|
|
889
|
+
return [{
|
|
890
|
+
Accept: 'application/json',
|
|
891
|
+
Cookie: raw
|
|
892
|
+
}];
|
|
893
|
+
}
|
|
894
|
+
return [
|
|
895
|
+
buildAuthHeaders(raw),
|
|
896
|
+
{ Accept: 'application/json', Cookie: `auth_token=${raw}` },
|
|
897
|
+
{ Accept: 'application/json', Cookie: `session=${raw}` },
|
|
898
|
+
{ Accept: 'application/json', Cookie: `__Secure-authjs.session-token=${raw}` }
|
|
899
|
+
];
|
|
900
|
+
}
|
|
901
|
+
|
|
794
902
|
function hasGatewayPathSegment(value) {
|
|
795
903
|
try {
|
|
796
904
|
const parsed = new URL(normalizeBaseUrl(value));
|
|
@@ -1047,12 +1155,27 @@ function buildBalanceProbeStrategies(baseUrl, channel = {}, token = '') {
|
|
|
1047
1155
|
add({ type: 'siliconflow-user-info', baseUrl, apiBase });
|
|
1048
1156
|
}
|
|
1049
1157
|
};
|
|
1158
|
+
const addNewCliStrategies = () => {
|
|
1159
|
+
for (const webBase of buildNewCliWebBaseCandidates(baseUrl, channel)) {
|
|
1160
|
+
add({
|
|
1161
|
+
type: 'newcli-dashboard',
|
|
1162
|
+
baseUrl,
|
|
1163
|
+
webBase,
|
|
1164
|
+
requiresDedicatedToken: !hasDedicatedBalanceToken(channel)
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
};
|
|
1050
1168
|
|
|
1051
1169
|
if (UNSUPPORTED_BALANCE_PLATFORMS.has(hintedPlatform)) {
|
|
1052
1170
|
add({ type: 'unsupported-balance', platform: hintedPlatform, baseUrl });
|
|
1053
1171
|
return strategies;
|
|
1054
1172
|
}
|
|
1055
1173
|
|
|
1174
|
+
if (hintedPlatform === 'newcli') {
|
|
1175
|
+
addNewCliStrategies();
|
|
1176
|
+
return strategies;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1056
1179
|
if (hintedPlatform === 'siliconflow') {
|
|
1057
1180
|
addSiliconFlowStrategies();
|
|
1058
1181
|
return strategies;
|
|
@@ -1224,6 +1347,21 @@ async function runSiliconFlowUserInfoStrategy(strategy, token) {
|
|
|
1224
1347
|
return buildSiliconFlowUserInfoSnapshot(payload);
|
|
1225
1348
|
}
|
|
1226
1349
|
|
|
1350
|
+
async function runNewCliDashboardStrategy(strategy, token, channel = {}) {
|
|
1351
|
+
if (strategy.requiresDedicatedToken || !hasDedicatedBalanceToken(channel)) {
|
|
1352
|
+
return makeHiddenSnapshot('newcli');
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
for (const headers of buildNewCliAuthHeaderCandidates(token)) {
|
|
1356
|
+
const payload = await tryRequestJson(joinUrl(strategy.webBase || strategy.baseUrl, '/api/user/dashboard'), {
|
|
1357
|
+
headers
|
|
1358
|
+
});
|
|
1359
|
+
const snapshot = buildNewCliDashboardSnapshot(payload);
|
|
1360
|
+
if (snapshot.visible) return snapshot;
|
|
1361
|
+
}
|
|
1362
|
+
return makeHiddenSnapshot('newcli');
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1227
1365
|
async function runBalanceStrategy(strategy, token, channel = {}) {
|
|
1228
1366
|
if (!strategy || !strategy.type) {
|
|
1229
1367
|
return { snapshot: makeHiddenSnapshot(), strategy };
|
|
@@ -1295,6 +1433,12 @@ async function runBalanceStrategy(strategy, token, channel = {}) {
|
|
|
1295
1433
|
strategy
|
|
1296
1434
|
};
|
|
1297
1435
|
}
|
|
1436
|
+
if (strategy.type === 'newcli-dashboard') {
|
|
1437
|
+
return {
|
|
1438
|
+
snapshot: await runNewCliDashboardStrategy(strategy, token, channel),
|
|
1439
|
+
strategy
|
|
1440
|
+
};
|
|
1441
|
+
}
|
|
1298
1442
|
|
|
1299
1443
|
return { snapshot: makeHiddenSnapshot(), strategy };
|
|
1300
1444
|
}
|
|
@@ -1320,6 +1464,7 @@ async function probeBalanceFromBase(baseUrl, channel, token) {
|
|
|
1320
1464
|
strategy.type?.startsWith('88code') ? '88code'
|
|
1321
1465
|
: strategy.type?.startsWith('openrouter') ? 'openrouter'
|
|
1322
1466
|
: strategy.type?.startsWith('siliconflow') ? 'siliconflow'
|
|
1467
|
+
: strategy.type?.startsWith('newcli') ? 'newcli'
|
|
1323
1468
|
: strategy.type?.startsWith('sub2api') ? 'sub2api'
|
|
1324
1469
|
: strategy.platform || null
|
|
1325
1470
|
);
|
|
@@ -1477,6 +1622,9 @@ function getChannelsForSource(source) {
|
|
|
1477
1622
|
if (source === 'opencode') {
|
|
1478
1623
|
return require('./opencode-channels').getChannels().channels || [];
|
|
1479
1624
|
}
|
|
1625
|
+
if (source === 'pi') {
|
|
1626
|
+
return require('./pi-channels').getChannels().channels || [];
|
|
1627
|
+
}
|
|
1480
1628
|
return [];
|
|
1481
1629
|
}
|
|
1482
1630
|
|
|
@@ -1586,8 +1734,10 @@ module.exports = {
|
|
|
1586
1734
|
build88CodeApiBaseCandidates,
|
|
1587
1735
|
buildOpenRouterApiBaseCandidates,
|
|
1588
1736
|
buildSiliconFlowApiBaseCandidates,
|
|
1737
|
+
buildNewCliWebBaseCandidates,
|
|
1589
1738
|
build88CodeUsageSnapshot,
|
|
1590
1739
|
build88CodeSubscriptionSnapshot,
|
|
1740
|
+
buildNewCliDashboardSnapshot,
|
|
1591
1741
|
buildBalanceProbeStrategies,
|
|
1592
1742
|
getEnabledBalanceChannels,
|
|
1593
1743
|
runBalanceStrategy,
|
|
@@ -2,6 +2,7 @@ const { getAllChannels } = require('./channels');
|
|
|
2
2
|
const { getChannels: getCodexChannels } = require('./codex-channels');
|
|
3
3
|
const { getChannels: getGeminiChannels } = require('./gemini-channels');
|
|
4
4
|
const { getChannels: getOpenCodeChannels } = require('./opencode-channels');
|
|
5
|
+
const { getChannels: getPiChannels } = require('./pi-channels');
|
|
5
6
|
const { isChannelAvailable, getChannelHealthStatus, setOnChannelFrozen, setChannelListProvider } = require('./channel-health');
|
|
6
7
|
|
|
7
8
|
const channelProviders = {
|
|
@@ -17,6 +18,10 @@ const channelProviders = {
|
|
|
17
18
|
opencode: () => {
|
|
18
19
|
const data = getOpenCodeChannels();
|
|
19
20
|
return Array.isArray(data?.channels) ? data.channels : [];
|
|
21
|
+
},
|
|
22
|
+
pi: () => {
|
|
23
|
+
const data = getPiChannels();
|
|
24
|
+
return Array.isArray(data?.channels) ? data.channels : [];
|
|
20
25
|
}
|
|
21
26
|
};
|
|
22
27
|
|
|
@@ -33,7 +38,8 @@ const schedulerStates = {
|
|
|
33
38
|
claude: createState(),
|
|
34
39
|
codex: createState(),
|
|
35
40
|
gemini: createState(),
|
|
36
|
-
opencode: createState()
|
|
41
|
+
opencode: createState(),
|
|
42
|
+
pi: createState()
|
|
37
43
|
};
|
|
38
44
|
|
|
39
45
|
function getState(source = 'claude') {
|
|
@@ -22,9 +22,10 @@ const {
|
|
|
22
22
|
|
|
23
23
|
// 默认仓库源
|
|
24
24
|
const DEFAULT_REPOS = [];
|
|
25
|
-
const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode'];
|
|
25
|
+
const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode', 'pi'];
|
|
26
26
|
const OPENCODE_CONFIG_DIR = NATIVE_PATHS.opencode.config;
|
|
27
|
-
const CLAUDE_COMMANDS_DIR =
|
|
27
|
+
const CLAUDE_COMMANDS_DIR = NATIVE_PATHS.claude.commands
|
|
28
|
+
|| path.join(NATIVE_PATHS.claude.dir || path.dirname(NATIVE_PATHS.claude.settings), 'commands');
|
|
28
29
|
const CODEX_COMMANDS_DIR = path.join(path.dirname(NATIVE_PATHS.codex.config), 'commands');
|
|
29
30
|
const GEMINI_COMMANDS_DIR = path.join(NATIVE_PATHS.gemini.dir, 'commands');
|
|
30
31
|
|
|
@@ -57,6 +58,11 @@ const PLATFORM_CONFIG = {
|
|
|
57
58
|
projectCommandsDir: (projectPath) => path.join(projectPath, '.gemini', 'commands'),
|
|
58
59
|
repoType: 'gemini-commands',
|
|
59
60
|
fileExtension: '.toml'
|
|
61
|
+
},
|
|
62
|
+
pi: {
|
|
63
|
+
userCommandsDir: NATIVE_PATHS.pi.commands || path.join(NATIVE_PATHS.pi.dir, 'commands'),
|
|
64
|
+
projectCommandsDir: (projectPath) => path.join(projectPath, '.omp', 'commands'),
|
|
65
|
+
repoType: 'pi-commands'
|
|
60
66
|
}
|
|
61
67
|
};
|
|
62
68
|
|
|
@@ -373,6 +379,9 @@ class CommandsService {
|
|
|
373
379
|
if (this.platform === 'gemini') {
|
|
374
380
|
return generateGeminiCommandToml({ description, body });
|
|
375
381
|
}
|
|
382
|
+
if (this.platform === 'pi') {
|
|
383
|
+
return body || '';
|
|
384
|
+
}
|
|
376
385
|
|
|
377
386
|
const frontmatterData = {};
|
|
378
387
|
if (description) frontmatterData.description = description;
|