codexmate 0.0.28 → 0.0.30
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/cli/builtin-proxy.js +107 -2
- package/cli/config-bootstrap.js +30 -12
- package/cli/config-health.js +117 -1
- package/cli/local-bridge.js +324 -0
- package/cli/openai-bridge.js +195 -31
- package/cli.js +245 -28
- package/lib/cli-webhook.js +126 -0
- package/package.json +1 -1
- package/web-ui/app.js +28 -8
- package/web-ui/index.html +1 -0
- package/web-ui/logic.codex.mjs +13 -0
- package/web-ui/modules/app.computed.dashboard.mjs +25 -2
- package/web-ui/modules/app.computed.session.mjs +22 -17
- package/web-ui/modules/app.methods.claude-config.mjs +12 -2
- package/web-ui/modules/app.methods.codex-config.mjs +25 -0
- package/web-ui/modules/app.methods.index.mjs +2 -0
- package/web-ui/modules/app.methods.navigation.mjs +39 -8
- package/web-ui/modules/app.methods.providers.mjs +125 -8
- package/web-ui/modules/app.methods.session-actions.mjs +1 -1
- package/web-ui/modules/app.methods.session-browser.mjs +1 -1
- package/web-ui/modules/app.methods.session-trash.mjs +3 -4
- package/web-ui/modules/app.methods.startup-claude.mjs +1 -0
- package/web-ui/modules/app.methods.webhook.mjs +79 -0
- package/web-ui/modules/i18n.dict.mjs +1109 -72
- package/web-ui/modules/i18n.mjs +9 -3
- package/web-ui/modules/skills.methods.mjs +1 -0
- package/web-ui/partials/index/layout-header.html +25 -0
- package/web-ui/partials/index/modals-basic.html +0 -3
- package/web-ui/partials/index/panel-config-claude.html +8 -2
- package/web-ui/partials/index/panel-config-codex.html +28 -3
- package/web-ui/partials/index/panel-dashboard.html +33 -0
- package/web-ui/partials/index/panel-market.html +3 -3
- package/web-ui/partials/index/panel-plugins.html +2 -2
- package/web-ui/partials/index/panel-sessions.html +1 -9
- package/web-ui/partials/index/panel-settings.html +71 -134
- package/web-ui/partials/index/panel-trash.html +88 -0
- package/web-ui/session-helpers.mjs +20 -2
- package/web-ui/styles/dashboard.css +132 -0
- package/web-ui/styles/docs-panel.css +63 -39
- package/web-ui/styles/layout-shell.css +54 -34
- package/web-ui/styles/plugins-panel.css +121 -80
- package/web-ui/styles/sessions-list.css +41 -43
- package/web-ui/styles/sessions-preview.css +34 -38
- package/web-ui/styles/sessions-toolbar-trash.css +31 -27
- package/web-ui/styles/settings-panel.css +197 -33
- package/web-ui/styles/skills-list.css +12 -10
- package/web-ui/styles/skills-market.css +67 -44
- package/web-ui/styles/trash-panel.css +90 -0
- package/web-ui/styles/webhook.css +81 -0
- package/web-ui/styles.css +2 -0
package/cli.js
CHANGED
|
@@ -83,7 +83,14 @@ const {
|
|
|
83
83
|
dispatchAutomationNotifiers,
|
|
84
84
|
formatTaskRunNotificationPayload
|
|
85
85
|
} = require('./lib/automation');
|
|
86
|
-
const {
|
|
86
|
+
const {
|
|
87
|
+
ALLOWED_EVENTS: WEBHOOK_ALLOWED_EVENTS,
|
|
88
|
+
defaultConfigPath: defaultWebhookConfigPath,
|
|
89
|
+
loadWebhookConfig,
|
|
90
|
+
saveWebhookConfig,
|
|
91
|
+
notifyWebhook
|
|
92
|
+
} = require('./lib/cli-webhook');
|
|
93
|
+
const { buildConfigHealthReport: buildConfigHealthReportCore, buildAllProvidersHealthReport: buildAllProvidersHealthReportCore } = require('./cli/config-health');
|
|
87
94
|
const { buildDoctorReport, buildDoctorLegacyPayload, renderDoctorMarkdown } = require('./cli/doctor-core');
|
|
88
95
|
const {
|
|
89
96
|
createAuthProfileController
|
|
@@ -100,6 +107,9 @@ const {
|
|
|
100
107
|
readOpenaiBridgeSettings,
|
|
101
108
|
resolveOpenaiBridgeUpstream
|
|
102
109
|
} = require('./cli/openai-bridge');
|
|
110
|
+
const {
|
|
111
|
+
createLocalBridgeHttpHandler
|
|
112
|
+
} = require('./cli/local-bridge');
|
|
103
113
|
const {
|
|
104
114
|
createOpenclawConfigController
|
|
105
115
|
} = require('./cli/openclaw-config');
|
|
@@ -181,6 +191,7 @@ const INIT_MARK_FILE = path.join(CONFIG_DIR, 'codexmate-init.json');
|
|
|
181
191
|
const BUILTIN_PROXY_SETTINGS_FILE = path.join(CONFIG_DIR, 'codexmate-proxy.json');
|
|
182
192
|
const BUILTIN_CLAUDE_PROXY_SETTINGS_FILE = path.join(CONFIG_DIR, 'codexmate-claude-proxy.json');
|
|
183
193
|
const OPENAI_BRIDGE_SETTINGS_FILE = path.join(CONFIG_DIR, 'codexmate-openai-bridge.json');
|
|
194
|
+
const LOCAL_BRIDGE_SETTINGS_FILE = path.join(CONFIG_DIR, 'codexmate-local-bridge.json');
|
|
184
195
|
const CODEX_SESSIONS_DIR = path.join(CONFIG_DIR, 'sessions');
|
|
185
196
|
const SESSION_TRASH_DIR = path.join(CONFIG_DIR, 'codexmate-session-trash');
|
|
186
197
|
const SESSION_TRASH_FILES_DIR = path.join(SESSION_TRASH_DIR, 'files');
|
|
@@ -261,6 +272,7 @@ const DEFAULT_EXTRACT_SUFFIXES = Object.freeze(['.json']);
|
|
|
261
272
|
const g_taskRunControllers = new Map();
|
|
262
273
|
let g_taskQueueProcessor = null;
|
|
263
274
|
const BUILTIN_PROXY_PROVIDER_NAME = 'codexmate-proxy';
|
|
275
|
+
const BUILTIN_LOCAL_PROVIDER_NAME = 'local';
|
|
264
276
|
const DEFAULT_BUILTIN_PROXY_SETTINGS = Object.freeze({
|
|
265
277
|
enabled: false,
|
|
266
278
|
host: '127.0.0.1',
|
|
@@ -304,8 +316,16 @@ const CLI_INSTALL_TARGETS = Object.freeze([
|
|
|
304
316
|
}
|
|
305
317
|
]);
|
|
306
318
|
|
|
307
|
-
const HTTP_KEEP_ALIVE_AGENT = new http.Agent({
|
|
308
|
-
|
|
319
|
+
const HTTP_KEEP_ALIVE_AGENT = new http.Agent({
|
|
320
|
+
keepAlive: true,
|
|
321
|
+
keepAliveMsecs: 1000,
|
|
322
|
+
maxFreeSockets: 4
|
|
323
|
+
});
|
|
324
|
+
const HTTPS_KEEP_ALIVE_AGENT = new https.Agent({
|
|
325
|
+
keepAlive: true,
|
|
326
|
+
keepAliveMsecs: 1000,
|
|
327
|
+
maxFreeSockets: 4
|
|
328
|
+
});
|
|
309
329
|
|
|
310
330
|
const openaiBridgeHandler = createOpenaiBridgeHttpHandler({
|
|
311
331
|
settingsFile: OPENAI_BRIDGE_SETTINGS_FILE,
|
|
@@ -315,6 +335,16 @@ const openaiBridgeHandler = createOpenaiBridgeHttpHandler({
|
|
|
315
335
|
httpsAgent: HTTPS_KEEP_ALIVE_AGENT
|
|
316
336
|
});
|
|
317
337
|
|
|
338
|
+
const localBridgeHandler = createLocalBridgeHttpHandler({
|
|
339
|
+
readConfigFn: readConfig,
|
|
340
|
+
openaiBridgeFile: OPENAI_BRIDGE_SETTINGS_FILE,
|
|
341
|
+
localBridgeSettingsFile: LOCAL_BRIDGE_SETTINGS_FILE,
|
|
342
|
+
expectedToken: typeof process.env.CODEXMATE_HTTP_TOKEN === 'string' ? process.env.CODEXMATE_HTTP_TOKEN.trim() : '',
|
|
343
|
+
maxBodySize: MAX_API_BODY_SIZE,
|
|
344
|
+
httpAgent: HTTP_KEEP_ALIVE_AGENT,
|
|
345
|
+
httpsAgent: HTTPS_KEEP_ALIVE_AGENT
|
|
346
|
+
});
|
|
347
|
+
|
|
318
348
|
function resolveWebPort() {
|
|
319
349
|
const raw = process.env.CODEXMATE_PORT;
|
|
320
350
|
if (!raw) return DEFAULT_WEB_PORT;
|
|
@@ -574,16 +604,17 @@ model_auto_compact_token_limit = ${DEFAULT_MODEL_AUTO_COMPACT_TOKEN_LIMIT}
|
|
|
574
604
|
disable_response_storage = true
|
|
575
605
|
approval_policy = "never"
|
|
576
606
|
sandbox_mode = "danger-full-access"
|
|
577
|
-
model_provider = "
|
|
607
|
+
model_provider = "local"
|
|
578
608
|
personality = "pragmatic"
|
|
579
609
|
web_search = "live"
|
|
580
610
|
|
|
581
|
-
[model_providers.
|
|
582
|
-
name = "
|
|
583
|
-
base_url = "
|
|
611
|
+
[model_providers.local]
|
|
612
|
+
name = "local"
|
|
613
|
+
base_url = "http://127.0.0.1:3737/bridge/local/v1"
|
|
584
614
|
wire_api = "responses"
|
|
585
|
-
requires_openai_auth =
|
|
586
|
-
preferred_auth_method = "
|
|
615
|
+
requires_openai_auth = true
|
|
616
|
+
preferred_auth_method = "codexmate"
|
|
617
|
+
codexmate_bridge = "local"
|
|
587
618
|
request_max_retries = 4
|
|
588
619
|
stream_max_retries = 10
|
|
589
620
|
stream_idle_timeout_ms = 300000
|
|
@@ -605,12 +636,16 @@ function isBuiltinProxyProvider(providerName) {
|
|
|
605
636
|
return typeof providerName === 'string' && providerName.trim().toLowerCase() === BUILTIN_PROXY_PROVIDER_NAME.toLowerCase();
|
|
606
637
|
}
|
|
607
638
|
|
|
639
|
+
function isLocalProvider(providerName) {
|
|
640
|
+
return typeof providerName === 'string' && providerName.trim().toLowerCase() === BUILTIN_LOCAL_PROVIDER_NAME.toLowerCase();
|
|
641
|
+
}
|
|
642
|
+
|
|
608
643
|
function isReservedProviderNameForCreation(providerName) {
|
|
609
|
-
return
|
|
644
|
+
return isLocalProvider(providerName);
|
|
610
645
|
}
|
|
611
646
|
|
|
612
647
|
function isBuiltinManagedProvider(providerName) {
|
|
613
|
-
return isBuiltinProxyProvider(providerName);
|
|
648
|
+
return isBuiltinProxyProvider(providerName) || isLocalProvider(providerName);
|
|
614
649
|
}
|
|
615
650
|
|
|
616
651
|
function isNonDeletableProvider(providerName) {
|
|
@@ -1646,6 +1681,7 @@ const {
|
|
|
1646
1681
|
DEFAULT_MODEL_AUTO_COMPACT_TOKEN_LIMIT,
|
|
1647
1682
|
CODEXMATE_MANAGED_MARKER,
|
|
1648
1683
|
BUILTIN_PROXY_PROVIDER_NAME,
|
|
1684
|
+
BUILTIN_LOCAL_PROVIDER_NAME,
|
|
1649
1685
|
EMPTY_CONFIG_FALLBACK_TEMPLATE
|
|
1650
1686
|
});
|
|
1651
1687
|
|
|
@@ -1711,6 +1747,14 @@ async function buildConfigHealthReport(params = {}) {
|
|
|
1711
1747
|
});
|
|
1712
1748
|
}
|
|
1713
1749
|
|
|
1750
|
+
async function buildAllProvidersHealthReport(params = {}) {
|
|
1751
|
+
return buildAllProvidersHealthReportCore(params, {
|
|
1752
|
+
readConfigOrVirtualDefault,
|
|
1753
|
+
readCurrentModels,
|
|
1754
|
+
probeJsonPost
|
|
1755
|
+
});
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1714
1758
|
function hasConfigLoadError(result) {
|
|
1715
1759
|
return !!(result
|
|
1716
1760
|
&& result.isVirtual
|
|
@@ -2044,7 +2088,7 @@ function addProviderToConfig(params = {}) {
|
|
|
2044
2088
|
return { error: '提供商名称不可用' };
|
|
2045
2089
|
}
|
|
2046
2090
|
if (isBuiltinProxyProvider(name) && !allowManaged) {
|
|
2047
|
-
return { error:
|
|
2091
|
+
return { error: `${"codexmate-proxy"} 为保留名称,不可手动添加` }; // keep literal for codexmate-proxy
|
|
2048
2092
|
}
|
|
2049
2093
|
|
|
2050
2094
|
ensureConfigDir();
|
|
@@ -2144,7 +2188,7 @@ function updateProviderInConfig(params = {}) {
|
|
|
2144
2188
|
return { error: 'URL 仅支持 http/https' };
|
|
2145
2189
|
}
|
|
2146
2190
|
if (isNonEditableProvider(name) && !allowManaged) {
|
|
2147
|
-
return { error:
|
|
2191
|
+
return { error: `${name} 为保留名称,不可编辑` };
|
|
2148
2192
|
}
|
|
2149
2193
|
|
|
2150
2194
|
try {
|
|
@@ -2159,7 +2203,7 @@ function deleteProviderFromConfig(params = {}) {
|
|
|
2159
2203
|
const name = typeof params.name === 'string' ? params.name.trim() : '';
|
|
2160
2204
|
if (!name) return { error: '名称不能为空' };
|
|
2161
2205
|
if (isNonDeletableProvider(name)) {
|
|
2162
|
-
return { error:
|
|
2206
|
+
return { error: `${name} 为保留名称,不可删除` };
|
|
2163
2207
|
}
|
|
2164
2208
|
if (!fs.existsSync(CONFIG_FILE)) {
|
|
2165
2209
|
return { error: 'config.toml 不存在' };
|
|
@@ -2187,7 +2231,7 @@ function deleteProviderFromConfig(params = {}) {
|
|
|
2187
2231
|
function performProviderDeletion(name, options = {}) {
|
|
2188
2232
|
const silent = !!options.silent;
|
|
2189
2233
|
if (isNonDeletableProvider(name)) {
|
|
2190
|
-
const msg =
|
|
2234
|
+
const msg = `${name} 为保留名称,不可删除`;
|
|
2191
2235
|
if (!silent) console.error('错误:', msg);
|
|
2192
2236
|
return { error: msg };
|
|
2193
2237
|
}
|
|
@@ -3639,12 +3683,19 @@ function readTotalTokensFromUsage(usage) {
|
|
|
3639
3683
|
return explicitTotal;
|
|
3640
3684
|
}
|
|
3641
3685
|
const inputTokens = readNonNegativeInteger(usage.input_tokens ?? usage.inputTokens);
|
|
3686
|
+
const cachedInputTokens = readNonNegativeInteger(
|
|
3687
|
+
usage.cached_input_tokens ?? usage.cachedInputTokens
|
|
3688
|
+
?? usage.cache_read_input_tokens ?? usage.cacheReadInputTokens
|
|
3689
|
+
);
|
|
3690
|
+
const cacheCreationInputTokens = readNonNegativeInteger(
|
|
3691
|
+
usage.cache_creation_input_tokens ?? usage.cacheCreationInputTokens
|
|
3692
|
+
);
|
|
3642
3693
|
const outputTokens = readNonNegativeInteger(usage.output_tokens ?? usage.outputTokens);
|
|
3643
3694
|
const reasoningOutputTokens = readNonNegativeInteger(usage.reasoning_output_tokens ?? usage.reasoningOutputTokens);
|
|
3644
|
-
if (inputTokens === null && outputTokens === null && reasoningOutputTokens === null) {
|
|
3695
|
+
if (inputTokens === null && cachedInputTokens === null && cacheCreationInputTokens === null && outputTokens === null && reasoningOutputTokens === null) {
|
|
3645
3696
|
return null;
|
|
3646
3697
|
}
|
|
3647
|
-
return (inputTokens || 0) + (outputTokens || 0) + (reasoningOutputTokens || 0);
|
|
3698
|
+
return (inputTokens || 0) + (cachedInputTokens || 0) + (cacheCreationInputTokens || 0) + (outputTokens || 0) + (reasoningOutputTokens || 0);
|
|
3648
3699
|
}
|
|
3649
3700
|
|
|
3650
3701
|
function readUsageTotalsFromUsage(usage) {
|
|
@@ -3652,19 +3703,26 @@ function readUsageTotalsFromUsage(usage) {
|
|
|
3652
3703
|
return null;
|
|
3653
3704
|
}
|
|
3654
3705
|
const inputTokens = readNonNegativeInteger(usage.input_tokens ?? usage.inputTokens);
|
|
3655
|
-
const cachedInputTokens = readNonNegativeInteger(
|
|
3706
|
+
const cachedInputTokens = readNonNegativeInteger(
|
|
3707
|
+
usage.cached_input_tokens ?? usage.cachedInputTokens
|
|
3708
|
+
?? usage.cache_read_input_tokens ?? usage.cacheReadInputTokens
|
|
3709
|
+
);
|
|
3710
|
+
const cacheCreationInputTokens = readNonNegativeInteger(
|
|
3711
|
+
usage.cache_creation_input_tokens ?? usage.cacheCreationInputTokens
|
|
3712
|
+
);
|
|
3656
3713
|
const outputTokens = readNonNegativeInteger(usage.output_tokens ?? usage.outputTokens);
|
|
3657
3714
|
const reasoningOutputTokens = readNonNegativeInteger(usage.reasoning_output_tokens ?? usage.reasoningOutputTokens);
|
|
3658
3715
|
const totalTokens = readNonNegativeInteger(usage.total_tokens ?? usage.totalTokens)
|
|
3659
|
-
?? ((inputTokens === null && cachedInputTokens === null && outputTokens === null && reasoningOutputTokens === null)
|
|
3716
|
+
?? ((inputTokens === null && cachedInputTokens === null && cacheCreationInputTokens === null && outputTokens === null && reasoningOutputTokens === null)
|
|
3660
3717
|
? null
|
|
3661
|
-
: ((inputTokens || 0) + (outputTokens || 0) + (reasoningOutputTokens || 0)));
|
|
3662
|
-
if (inputTokens === null && cachedInputTokens === null && outputTokens === null && reasoningOutputTokens === null && totalTokens === null) {
|
|
3718
|
+
: ((inputTokens || 0) + (cachedInputTokens || 0) + (cacheCreationInputTokens || 0) + (outputTokens || 0) + (reasoningOutputTokens || 0)));
|
|
3719
|
+
if (inputTokens === null && cachedInputTokens === null && cacheCreationInputTokens === null && outputTokens === null && reasoningOutputTokens === null && totalTokens === null) {
|
|
3663
3720
|
return null;
|
|
3664
3721
|
}
|
|
3665
3722
|
return {
|
|
3666
3723
|
inputTokens,
|
|
3667
3724
|
cachedInputTokens,
|
|
3725
|
+
cacheCreationInputTokens,
|
|
3668
3726
|
outputTokens,
|
|
3669
3727
|
reasoningOutputTokens,
|
|
3670
3728
|
totalTokens
|
|
@@ -3690,6 +3748,7 @@ function applyUsageTotalsToState(state, usageTotals) {
|
|
|
3690
3748
|
const pairs = [
|
|
3691
3749
|
['inputTokens', usageTotals.inputTokens],
|
|
3692
3750
|
['cachedInputTokens', usageTotals.cachedInputTokens],
|
|
3751
|
+
['cacheCreationInputTokens', usageTotals.cacheCreationInputTokens],
|
|
3693
3752
|
['outputTokens', usageTotals.outputTokens],
|
|
3694
3753
|
['reasoningOutputTokens', usageTotals.reasoningOutputTokens],
|
|
3695
3754
|
['totalTokens', usageTotals.totalTokens]
|
|
@@ -3940,12 +3999,13 @@ function parseCodexSessionSummary(filePath, options = {}) {
|
|
|
3940
3999
|
let contextWindow = 0;
|
|
3941
4000
|
let inputTokens = 0;
|
|
3942
4001
|
let cachedInputTokens = 0;
|
|
4002
|
+
let cacheCreationInputTokens = 0;
|
|
3943
4003
|
let outputTokens = 0;
|
|
3944
4004
|
let reasoningOutputTokens = 0;
|
|
3945
4005
|
let provider = 'codex';
|
|
3946
4006
|
let model = '';
|
|
3947
4007
|
const models = [];
|
|
3948
|
-
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, outputTokens, reasoningOutputTokens };
|
|
4008
|
+
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, cacheCreationInputTokens, outputTokens, reasoningOutputTokens };
|
|
3949
4009
|
const previewMessages = [];
|
|
3950
4010
|
|
|
3951
4011
|
for (const record of records) {
|
|
@@ -3958,6 +4018,7 @@ function parseCodexSessionSummary(filePath, options = {}) {
|
|
|
3958
4018
|
contextWindow = usageState.contextWindow || 0;
|
|
3959
4019
|
inputTokens = usageState.inputTokens || 0;
|
|
3960
4020
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4021
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
3961
4022
|
outputTokens = usageState.outputTokens || 0;
|
|
3962
4023
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
3963
4024
|
|
|
@@ -3992,6 +4053,7 @@ function parseCodexSessionSummary(filePath, options = {}) {
|
|
|
3992
4053
|
contextWindow = usageState.contextWindow || 0;
|
|
3993
4054
|
inputTokens = usageState.inputTokens || 0;
|
|
3994
4055
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4056
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
3995
4057
|
outputTokens = usageState.outputTokens || 0;
|
|
3996
4058
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
3997
4059
|
provider = readExplicitSessionProviderFromRecord(record) || provider;
|
|
@@ -4051,6 +4113,7 @@ function parseCodexSessionSummary(filePath, options = {}) {
|
|
|
4051
4113
|
contextWindow,
|
|
4052
4114
|
inputTokens,
|
|
4053
4115
|
cachedInputTokens,
|
|
4116
|
+
cacheCreationInputTokens,
|
|
4054
4117
|
outputTokens,
|
|
4055
4118
|
reasoningOutputTokens,
|
|
4056
4119
|
__messageCountExact: isSessionSummaryMessageCountExact(stat, summaryReadBytes),
|
|
@@ -4087,12 +4150,13 @@ function parseClaudeSessionSummary(filePath, options = {}) {
|
|
|
4087
4150
|
let contextWindow = 0;
|
|
4088
4151
|
let inputTokens = 0;
|
|
4089
4152
|
let cachedInputTokens = 0;
|
|
4153
|
+
let cacheCreationInputTokens = 0;
|
|
4090
4154
|
let outputTokens = 0;
|
|
4091
4155
|
let reasoningOutputTokens = 0;
|
|
4092
4156
|
let provider = 'claude';
|
|
4093
4157
|
let model = '';
|
|
4094
4158
|
const models = [];
|
|
4095
|
-
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, outputTokens, reasoningOutputTokens };
|
|
4159
|
+
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, cacheCreationInputTokens, outputTokens, reasoningOutputTokens };
|
|
4096
4160
|
const previewMessages = [];
|
|
4097
4161
|
let createdAt = '';
|
|
4098
4162
|
let updatedAt = stat.mtime.toISOString();
|
|
@@ -4110,6 +4174,7 @@ function parseClaudeSessionSummary(filePath, options = {}) {
|
|
|
4110
4174
|
contextWindow = usageState.contextWindow || 0;
|
|
4111
4175
|
inputTokens = usageState.inputTokens || 0;
|
|
4112
4176
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4177
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
4113
4178
|
outputTokens = usageState.outputTokens || 0;
|
|
4114
4179
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
4115
4180
|
|
|
@@ -4143,6 +4208,7 @@ function parseClaudeSessionSummary(filePath, options = {}) {
|
|
|
4143
4208
|
contextWindow = usageState.contextWindow || 0;
|
|
4144
4209
|
inputTokens = usageState.inputTokens || 0;
|
|
4145
4210
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4211
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
4146
4212
|
outputTokens = usageState.outputTokens || 0;
|
|
4147
4213
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
4148
4214
|
provider = readExplicitSessionProviderFromRecord(record) || provider;
|
|
@@ -4201,6 +4267,7 @@ function parseClaudeSessionSummary(filePath, options = {}) {
|
|
|
4201
4267
|
contextWindow,
|
|
4202
4268
|
inputTokens,
|
|
4203
4269
|
cachedInputTokens,
|
|
4270
|
+
cacheCreationInputTokens,
|
|
4204
4271
|
outputTokens,
|
|
4205
4272
|
reasoningOutputTokens,
|
|
4206
4273
|
__messageCountExact: isSessionSummaryMessageCountExact(stat, summaryReadBytes),
|
|
@@ -4237,12 +4304,13 @@ function parseCodeBuddySessionSummary(filePath, options = {}) {
|
|
|
4237
4304
|
let contextWindow = 0;
|
|
4238
4305
|
let inputTokens = 0;
|
|
4239
4306
|
let cachedInputTokens = 0;
|
|
4307
|
+
let cacheCreationInputTokens = 0;
|
|
4240
4308
|
let outputTokens = 0;
|
|
4241
4309
|
let reasoningOutputTokens = 0;
|
|
4242
4310
|
let provider = 'codebuddy';
|
|
4243
4311
|
let model = '';
|
|
4244
4312
|
const models = [];
|
|
4245
|
-
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, outputTokens, reasoningOutputTokens };
|
|
4313
|
+
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, cacheCreationInputTokens, outputTokens, reasoningOutputTokens };
|
|
4246
4314
|
const previewMessages = [];
|
|
4247
4315
|
let createdAt = '';
|
|
4248
4316
|
let updatedAt = stat.mtime.toISOString();
|
|
@@ -4260,6 +4328,7 @@ function parseCodeBuddySessionSummary(filePath, options = {}) {
|
|
|
4260
4328
|
contextWindow = usageState.contextWindow || 0;
|
|
4261
4329
|
inputTokens = usageState.inputTokens || 0;
|
|
4262
4330
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4331
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
4263
4332
|
outputTokens = usageState.outputTokens || 0;
|
|
4264
4333
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
4265
4334
|
|
|
@@ -4298,6 +4367,7 @@ function parseCodeBuddySessionSummary(filePath, options = {}) {
|
|
|
4298
4367
|
contextWindow = usageState.contextWindow || 0;
|
|
4299
4368
|
inputTokens = usageState.inputTokens || 0;
|
|
4300
4369
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4370
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
4301
4371
|
outputTokens = usageState.outputTokens || 0;
|
|
4302
4372
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
4303
4373
|
provider = readExplicitSessionProviderFromRecord(record) || provider;
|
|
@@ -4358,6 +4428,7 @@ function parseCodeBuddySessionSummary(filePath, options = {}) {
|
|
|
4358
4428
|
contextWindow,
|
|
4359
4429
|
inputTokens,
|
|
4360
4430
|
cachedInputTokens,
|
|
4431
|
+
cacheCreationInputTokens,
|
|
4361
4432
|
outputTokens,
|
|
4362
4433
|
reasoningOutputTokens,
|
|
4363
4434
|
__messageCountExact: isSessionSummaryMessageCountExact(stat, summaryReadBytes),
|
|
@@ -4647,17 +4718,19 @@ function listClaudeSessions(limit, options = {}) {
|
|
|
4647
4718
|
let contextWindow = 0;
|
|
4648
4719
|
let inputTokens = 0;
|
|
4649
4720
|
let cachedInputTokens = 0;
|
|
4721
|
+
let cacheCreationInputTokens = 0;
|
|
4650
4722
|
let outputTokens = 0;
|
|
4651
4723
|
let reasoningOutputTokens = 0;
|
|
4652
4724
|
let model = typeof entry.model === 'string' ? entry.model.trim() : '';
|
|
4653
4725
|
const models = model ? [model] : [];
|
|
4654
4726
|
|
|
4655
|
-
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, outputTokens, reasoningOutputTokens };
|
|
4727
|
+
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, cacheCreationInputTokens, outputTokens, reasoningOutputTokens };
|
|
4656
4728
|
applySessionUsageSummaryFromIndexEntry(usageState, entry);
|
|
4657
4729
|
totalTokens = usageState.totalTokens || 0;
|
|
4658
4730
|
contextWindow = usageState.contextWindow || 0;
|
|
4659
4731
|
inputTokens = usageState.inputTokens || 0;
|
|
4660
4732
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4733
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
4661
4734
|
outputTokens = usageState.outputTokens || 0;
|
|
4662
4735
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
4663
4736
|
|
|
@@ -4688,6 +4761,7 @@ function listClaudeSessions(limit, options = {}) {
|
|
|
4688
4761
|
contextWindow = usageState.contextWindow || 0;
|
|
4689
4762
|
inputTokens = usageState.inputTokens || 0;
|
|
4690
4763
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4764
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
4691
4765
|
outputTokens = usageState.outputTokens || 0;
|
|
4692
4766
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
4693
4767
|
const filteredQuickMessages = removeLeadingSystemMessage(quickMessages);
|
|
@@ -4712,6 +4786,7 @@ function listClaudeSessions(limit, options = {}) {
|
|
|
4712
4786
|
contextWindow = usageState.contextWindow || 0;
|
|
4713
4787
|
inputTokens = usageState.inputTokens || 0;
|
|
4714
4788
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4789
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
4715
4790
|
outputTokens = usageState.outputTokens || 0;
|
|
4716
4791
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
4717
4792
|
|
|
@@ -4735,6 +4810,7 @@ function listClaudeSessions(limit, options = {}) {
|
|
|
4735
4810
|
contextWindow,
|
|
4736
4811
|
inputTokens,
|
|
4737
4812
|
cachedInputTokens,
|
|
4813
|
+
cacheCreationInputTokens,
|
|
4738
4814
|
outputTokens,
|
|
4739
4815
|
reasoningOutputTokens,
|
|
4740
4816
|
model,
|
|
@@ -5376,6 +5452,100 @@ async function ensureBuiltinProxyForCodexDefault(params = {}) {
|
|
|
5376
5452
|
return { error: '该功能已移除' };
|
|
5377
5453
|
}
|
|
5378
5454
|
|
|
5455
|
+
function readLocalBridgeSettings() {
|
|
5456
|
+
const defaults = { enabled: false, lastActiveProvider: '', lastModel: '', excludedProviders: [] };
|
|
5457
|
+
try {
|
|
5458
|
+
if (!fs.existsSync(LOCAL_BRIDGE_SETTINGS_FILE)) return defaults;
|
|
5459
|
+
const raw = JSON.parse(fs.readFileSync(LOCAL_BRIDGE_SETTINGS_FILE, 'utf-8'));
|
|
5460
|
+
return {
|
|
5461
|
+
enabled: !!raw.enabled,
|
|
5462
|
+
lastActiveProvider: typeof raw.lastActiveProvider === 'string' ? raw.lastActiveProvider.trim() : '',
|
|
5463
|
+
lastModel: typeof raw.lastModel === 'string' ? raw.lastModel.trim() : '',
|
|
5464
|
+
excludedProviders: Array.isArray(raw.excludedProviders) ? raw.excludedProviders.filter(p => typeof p === 'string') : []
|
|
5465
|
+
};
|
|
5466
|
+
} catch (e) {
|
|
5467
|
+
return defaults;
|
|
5468
|
+
}
|
|
5469
|
+
}
|
|
5470
|
+
|
|
5471
|
+
function writeLocalBridgeSettings(settings) {
|
|
5472
|
+
fs.writeFileSync(LOCAL_BRIDGE_SETTINGS_FILE, JSON.stringify(settings, null, 2), 'utf-8');
|
|
5473
|
+
}
|
|
5474
|
+
|
|
5475
|
+
function toggleLocalBridgeProvider(params = {}) {
|
|
5476
|
+
const enable = !!params.enable;
|
|
5477
|
+
const settings = readLocalBridgeSettings();
|
|
5478
|
+
try {
|
|
5479
|
+
const config = readConfig();
|
|
5480
|
+
const currentProvider = typeof config.model_provider === 'string' ? config.model_provider.trim() : '';
|
|
5481
|
+
const currentModel = typeof config.model === 'string' ? config.model.trim() : '';
|
|
5482
|
+
|
|
5483
|
+
if (enable) {
|
|
5484
|
+
if (currentProvider === 'local') return { success: true, enabled: true, notice: '已启用 local 转换' };
|
|
5485
|
+
settings.lastActiveProvider = currentProvider;
|
|
5486
|
+
settings.lastModel = currentModel;
|
|
5487
|
+
settings.enabled = true;
|
|
5488
|
+
writeLocalBridgeSettings(settings);
|
|
5489
|
+
let content = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
5490
|
+
content = content.replace(/^(model_provider\s*=\s*)(["']).*?(["'])/m, `$1$2local$3`);
|
|
5491
|
+
writeConfig(content);
|
|
5492
|
+
return { success: true, enabled: true, previousProvider: currentProvider };
|
|
5493
|
+
} else {
|
|
5494
|
+
if (currentProvider !== 'local') {
|
|
5495
|
+
settings.enabled = false;
|
|
5496
|
+
writeLocalBridgeSettings(settings);
|
|
5497
|
+
return { success: true, enabled: false, notice: 'local 转换未启用' };
|
|
5498
|
+
}
|
|
5499
|
+
const restoreProvider = settings.lastActiveProvider || '';
|
|
5500
|
+
if (!restoreProvider) {
|
|
5501
|
+
settings.enabled = false;
|
|
5502
|
+
writeLocalBridgeSettings(settings);
|
|
5503
|
+
return { success: true, enabled: false, notice: '已关闭 local 转换(无历史 provider 可恢复)' };
|
|
5504
|
+
}
|
|
5505
|
+
let content = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
5506
|
+
content = content.replace(/^(model_provider\s*=\s*)(["']).*?(["'])/m, `$1$2${restoreProvider}$3`);
|
|
5507
|
+
if (settings.lastModel) {
|
|
5508
|
+
content = content.replace(/^(model\s*=\s*)(["']).*?(["'])/m, `$1$2${settings.lastModel}$3`);
|
|
5509
|
+
}
|
|
5510
|
+
writeConfig(content);
|
|
5511
|
+
settings.enabled = false;
|
|
5512
|
+
writeLocalBridgeSettings(settings);
|
|
5513
|
+
return { success: true, enabled: false, restoredProvider: restoreProvider, restoredModel: settings.lastModel };
|
|
5514
|
+
}
|
|
5515
|
+
} catch (e) {
|
|
5516
|
+
return { error: e && e.message ? e.message : '操作失败' };
|
|
5517
|
+
}
|
|
5518
|
+
}
|
|
5519
|
+
|
|
5520
|
+
function getLocalBridgeStatus() {
|
|
5521
|
+
const settings = readLocalBridgeSettings();
|
|
5522
|
+
let currentProvider = '';
|
|
5523
|
+
try {
|
|
5524
|
+
const config = readConfig();
|
|
5525
|
+
currentProvider = typeof config.model_provider === 'string' ? config.model_provider.trim() : '';
|
|
5526
|
+
} catch (e) { /* ignore */ }
|
|
5527
|
+
return {
|
|
5528
|
+
enabled: settings.enabled,
|
|
5529
|
+
active: currentProvider === 'local',
|
|
5530
|
+
excludedProviders: settings.excludedProviders,
|
|
5531
|
+
lastActiveProvider: settings.lastActiveProvider,
|
|
5532
|
+
lastModel: settings.lastModel
|
|
5533
|
+
};
|
|
5534
|
+
}
|
|
5535
|
+
|
|
5536
|
+
function setLocalBridgeExcludedProviders(params = {}) {
|
|
5537
|
+
const names = Array.isArray(params.names) ? params.names.filter(n => typeof n === 'string' && n.trim()) : [];
|
|
5538
|
+
const settings = readLocalBridgeSettings();
|
|
5539
|
+
settings.excludedProviders = names;
|
|
5540
|
+
writeLocalBridgeSettings(settings);
|
|
5541
|
+
return { success: true, excludedProviders: names };
|
|
5542
|
+
}
|
|
5543
|
+
|
|
5544
|
+
function getLocalBridgeExcludedProviders() {
|
|
5545
|
+
const settings = readLocalBridgeSettings();
|
|
5546
|
+
return { excludedProviders: settings.excludedProviders };
|
|
5547
|
+
}
|
|
5548
|
+
|
|
5379
5549
|
function removeClaudeSessionIndexEntry(indexPath, sessionFilePath, sessionId) {
|
|
5380
5550
|
if (!indexPath || !fs.existsSync(indexPath)) {
|
|
5381
5551
|
return { removed: false, entry: null };
|
|
@@ -8085,8 +8255,8 @@ function cmdAdd(name, baseUrl, apiKey, silent = false, options = {}) {
|
|
|
8085
8255
|
throw new Error('提供商名称不可用');
|
|
8086
8256
|
}
|
|
8087
8257
|
if (isBuiltinProxyProvider(providerName)) {
|
|
8088
|
-
if (!silent) console.error(
|
|
8089
|
-
throw new Error(
|
|
8258
|
+
if (!silent) console.error(`错误: ${providerName} 为保留名称,不可手动添加`);
|
|
8259
|
+
throw new Error(`${providerName} 为保留名称,不可手动添加`);
|
|
8090
8260
|
}
|
|
8091
8261
|
if (!isValidHttpUrl(providerBaseUrl)) {
|
|
8092
8262
|
if (!silent) console.error('错误: URL 仅支持 http/https');
|
|
@@ -8182,7 +8352,7 @@ function cmdUpdate(name, baseUrl, apiKey, silent = false, options = {}) {
|
|
|
8182
8352
|
throw new Error('提供商名称必填');
|
|
8183
8353
|
}
|
|
8184
8354
|
if (isNonEditableProvider(name) && !allowManaged) {
|
|
8185
|
-
const msg =
|
|
8355
|
+
const msg = `${name} 为保留名称,不可编辑`;
|
|
8186
8356
|
if (!silent) console.error(`错误: ${msg}`);
|
|
8187
8357
|
throw new Error(msg);
|
|
8188
8358
|
}
|
|
@@ -9914,6 +10084,9 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
|
|
|
9914
10084
|
});
|
|
9915
10085
|
res.end(body, 'utf-8');
|
|
9916
10086
|
};
|
|
10087
|
+
if (typeof localBridgeHandler === 'function' && localBridgeHandler(req, res)) {
|
|
10088
|
+
return;
|
|
10089
|
+
}
|
|
9917
10090
|
if (typeof openaiBridgeHandler === 'function' && openaiBridgeHandler(req, res)) {
|
|
9918
10091
|
return;
|
|
9919
10092
|
}
|
|
@@ -10108,6 +10281,9 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
|
|
|
10108
10281
|
case 'config-health-check':
|
|
10109
10282
|
result = await buildConfigHealthReport(params || {});
|
|
10110
10283
|
break;
|
|
10284
|
+
case 'providers-health':
|
|
10285
|
+
result = await buildAllProvidersHealthReport(params || {});
|
|
10286
|
+
break;
|
|
10111
10287
|
case 'doctor':
|
|
10112
10288
|
{
|
|
10113
10289
|
const doctorParams = isPlainObject(params) ? params : {};
|
|
@@ -10134,6 +10310,10 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
|
|
|
10134
10310
|
break;
|
|
10135
10311
|
case 'apply-claude-md-file':
|
|
10136
10312
|
result = applyClaudeMdFile(params || {});
|
|
10313
|
+
if (result && !result.error) {
|
|
10314
|
+
const mdTarget = (params && params.targetPath) ? String(params.targetPath) : 'CLAUDE.md';
|
|
10315
|
+
notifyWebhook('claude-md-edit', 'CLAUDE.md modified: ' + mdTarget, { targetPath: mdTarget }).catch(function () {});
|
|
10316
|
+
}
|
|
10137
10317
|
break;
|
|
10138
10318
|
case 'preview-agents-diff':
|
|
10139
10319
|
result = buildAgentsDiff(params || {});
|
|
@@ -10209,7 +10389,32 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
|
|
|
10209
10389
|
break;
|
|
10210
10390
|
case 'apply-claude-config':
|
|
10211
10391
|
result = applyToClaudeSettings(params.config);
|
|
10392
|
+
if (result && !result.error) {
|
|
10393
|
+
const cfgName = (params && params.config && typeof params.config.name === 'string') ? params.config.name : '';
|
|
10394
|
+
const cfgFrom = (params && typeof params.previousName === 'string') ? params.previousName : '';
|
|
10395
|
+
const summary = cfgFrom
|
|
10396
|
+
? ('Provider switched: ' + cfgFrom + ' -> ' + cfgName)
|
|
10397
|
+
: ('Provider applied: ' + cfgName);
|
|
10398
|
+
notifyWebhook('provider-switch', summary, { name: cfgName, previousName: cfgFrom }).catch(function () {});
|
|
10399
|
+
}
|
|
10400
|
+
break;
|
|
10401
|
+
case 'get-webhook-config':
|
|
10402
|
+
result = loadWebhookConfig();
|
|
10403
|
+
break;
|
|
10404
|
+
case 'set-webhook-config':
|
|
10405
|
+
result = saveWebhookConfig(params && params.config ? params.config : {});
|
|
10212
10406
|
break;
|
|
10407
|
+
case 'test-webhook': {
|
|
10408
|
+
const overrideCfg = params && params.config ? params.config : null;
|
|
10409
|
+
const probe = await notifyWebhook(
|
|
10410
|
+
'provider-switch',
|
|
10411
|
+
'codexmate webhook test ping',
|
|
10412
|
+
{ test: true },
|
|
10413
|
+
overrideCfg ? { config: overrideCfg } : {}
|
|
10414
|
+
);
|
|
10415
|
+
result = probe;
|
|
10416
|
+
break;
|
|
10417
|
+
}
|
|
10213
10418
|
case 'export-claude-share':
|
|
10214
10419
|
result = buildClaudeSharePayload(params && params.config ? params.config : {});
|
|
10215
10420
|
break;
|
|
@@ -10421,6 +10626,18 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
|
|
|
10421
10626
|
case 'proxy-apply-provider':
|
|
10422
10627
|
result = applyBuiltinProxyProvider(params || {});
|
|
10423
10628
|
break;
|
|
10629
|
+
case 'local-bridge-toggle':
|
|
10630
|
+
result = toggleLocalBridgeProvider(params || {});
|
|
10631
|
+
break;
|
|
10632
|
+
case 'local-bridge-status':
|
|
10633
|
+
result = getLocalBridgeStatus();
|
|
10634
|
+
break;
|
|
10635
|
+
case 'local-bridge-set-excluded':
|
|
10636
|
+
result = setLocalBridgeExcludedProviders(params || {});
|
|
10637
|
+
break;
|
|
10638
|
+
case 'local-bridge-get-excluded':
|
|
10639
|
+
result = getLocalBridgeExcludedProviders();
|
|
10640
|
+
break;
|
|
10424
10641
|
case 'workflow-list':
|
|
10425
10642
|
result = listWorkflowDefinitions();
|
|
10426
10643
|
break;
|