codexmate 0.0.27 → 0.0.29
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 +1 -1
- package/README.zh.md +1 -1
- package/cli/builtin-proxy.js +430 -4
- package/cli/openai-bridge.js +498 -13
- package/cli.js +130 -41
- package/lib/cli-models-utils.js +71 -10
- package/lib/cli-webhook.js +126 -0
- package/package.json +76 -74
- package/plugins/prompt-templates/computed.mjs +1 -1
- package/plugins/prompt-templates/methods.mjs +0 -66
- package/plugins/prompt-templates/overview.mjs +1 -0
- package/web-ui/app.js +21 -16
- package/web-ui/index.html +1 -0
- package/web-ui/logic.codex.mjs +69 -0
- package/web-ui/modules/app.computed.dashboard.mjs +54 -0
- package/web-ui/modules/app.computed.session.mjs +22 -17
- package/web-ui/modules/app.methods.claude-config.mjs +24 -8
- package/web-ui/modules/app.methods.codex-config.mjs +35 -3
- package/web-ui/modules/app.methods.index.mjs +2 -0
- package/web-ui/modules/app.methods.navigation.mjs +21 -3
- package/web-ui/modules/app.methods.providers.mjs +96 -7
- package/web-ui/modules/app.methods.session-actions.mjs +3 -6
- package/web-ui/modules/app.methods.session-browser.mjs +1 -6
- package/web-ui/modules/app.methods.session-trash.mjs +6 -7
- package/web-ui/modules/app.methods.startup-claude.mjs +8 -1
- package/web-ui/modules/app.methods.webhook.mjs +79 -0
- package/web-ui/modules/i18n.dict.mjs +1104 -104
- package/web-ui/modules/i18n.mjs +9 -3
- package/web-ui/modules/provider-url-display.mjs +17 -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 +10 -3
- package/web-ui/partials/index/panel-config-codex.html +44 -4
- package/web-ui/partials/index/panel-plugins.html +3 -29
- package/web-ui/partials/index/panel-sessions.html +0 -10
- package/web-ui/partials/index/panel-settings.html +93 -177
- package/web-ui/partials/index/panel-trash.html +88 -0
- package/web-ui/session-helpers.mjs +2 -2
- package/web-ui/styles/base-theme.css +47 -34
- package/web-ui/styles/controls-forms.css +27 -28
- package/web-ui/styles/docs-panel.css +63 -39
- package/web-ui/styles/layout-shell.css +69 -46
- package/web-ui/styles/modals-core.css +12 -10
- package/web-ui/styles/navigation-panels.css +36 -35
- package/web-ui/styles/responsive.css +4 -4
- package/web-ui/styles/sessions-list.css +10 -6
- package/web-ui/styles/settings-panel.css +197 -33
- package/web-ui/styles/titles-cards.css +90 -26
- 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,6 +83,13 @@ const {
|
|
|
83
83
|
dispatchAutomationNotifiers,
|
|
84
84
|
formatTaskRunNotificationPayload
|
|
85
85
|
} = require('./lib/automation');
|
|
86
|
+
const {
|
|
87
|
+
ALLOWED_EVENTS: WEBHOOK_ALLOWED_EVENTS,
|
|
88
|
+
defaultConfigPath: defaultWebhookConfigPath,
|
|
89
|
+
loadWebhookConfig,
|
|
90
|
+
saveWebhookConfig,
|
|
91
|
+
notifyWebhook
|
|
92
|
+
} = require('./lib/cli-webhook');
|
|
86
93
|
const { buildConfigHealthReport: buildConfigHealthReportCore } = require('./cli/config-health');
|
|
87
94
|
const { buildDoctorReport, buildDoctorLegacyPayload, renderDoctorMarkdown } = require('./cli/doctor-core');
|
|
88
95
|
const {
|
|
@@ -304,8 +311,16 @@ const CLI_INSTALL_TARGETS = Object.freeze([
|
|
|
304
311
|
}
|
|
305
312
|
]);
|
|
306
313
|
|
|
307
|
-
const HTTP_KEEP_ALIVE_AGENT = new http.Agent({
|
|
308
|
-
|
|
314
|
+
const HTTP_KEEP_ALIVE_AGENT = new http.Agent({
|
|
315
|
+
keepAlive: true,
|
|
316
|
+
keepAliveMsecs: 1000,
|
|
317
|
+
maxFreeSockets: 4
|
|
318
|
+
});
|
|
319
|
+
const HTTPS_KEEP_ALIVE_AGENT = new https.Agent({
|
|
320
|
+
keepAlive: true,
|
|
321
|
+
keepAliveMsecs: 1000,
|
|
322
|
+
maxFreeSockets: 4
|
|
323
|
+
});
|
|
309
324
|
|
|
310
325
|
const openaiBridgeHandler = createOpenaiBridgeHttpHandler({
|
|
311
326
|
settingsFile: OPENAI_BRIDGE_SETTINGS_FILE,
|
|
@@ -3639,12 +3654,19 @@ function readTotalTokensFromUsage(usage) {
|
|
|
3639
3654
|
return explicitTotal;
|
|
3640
3655
|
}
|
|
3641
3656
|
const inputTokens = readNonNegativeInteger(usage.input_tokens ?? usage.inputTokens);
|
|
3657
|
+
const cachedInputTokens = readNonNegativeInteger(
|
|
3658
|
+
usage.cached_input_tokens ?? usage.cachedInputTokens
|
|
3659
|
+
?? usage.cache_read_input_tokens ?? usage.cacheReadInputTokens
|
|
3660
|
+
);
|
|
3661
|
+
const cacheCreationInputTokens = readNonNegativeInteger(
|
|
3662
|
+
usage.cache_creation_input_tokens ?? usage.cacheCreationInputTokens
|
|
3663
|
+
);
|
|
3642
3664
|
const outputTokens = readNonNegativeInteger(usage.output_tokens ?? usage.outputTokens);
|
|
3643
3665
|
const reasoningOutputTokens = readNonNegativeInteger(usage.reasoning_output_tokens ?? usage.reasoningOutputTokens);
|
|
3644
|
-
if (inputTokens === null && outputTokens === null && reasoningOutputTokens === null) {
|
|
3666
|
+
if (inputTokens === null && cachedInputTokens === null && cacheCreationInputTokens === null && outputTokens === null && reasoningOutputTokens === null) {
|
|
3645
3667
|
return null;
|
|
3646
3668
|
}
|
|
3647
|
-
return (inputTokens || 0) + (outputTokens || 0) + (reasoningOutputTokens || 0);
|
|
3669
|
+
return (inputTokens || 0) + (cachedInputTokens || 0) + (cacheCreationInputTokens || 0) + (outputTokens || 0) + (reasoningOutputTokens || 0);
|
|
3648
3670
|
}
|
|
3649
3671
|
|
|
3650
3672
|
function readUsageTotalsFromUsage(usage) {
|
|
@@ -3652,19 +3674,26 @@ function readUsageTotalsFromUsage(usage) {
|
|
|
3652
3674
|
return null;
|
|
3653
3675
|
}
|
|
3654
3676
|
const inputTokens = readNonNegativeInteger(usage.input_tokens ?? usage.inputTokens);
|
|
3655
|
-
const cachedInputTokens = readNonNegativeInteger(
|
|
3677
|
+
const cachedInputTokens = readNonNegativeInteger(
|
|
3678
|
+
usage.cached_input_tokens ?? usage.cachedInputTokens
|
|
3679
|
+
?? usage.cache_read_input_tokens ?? usage.cacheReadInputTokens
|
|
3680
|
+
);
|
|
3681
|
+
const cacheCreationInputTokens = readNonNegativeInteger(
|
|
3682
|
+
usage.cache_creation_input_tokens ?? usage.cacheCreationInputTokens
|
|
3683
|
+
);
|
|
3656
3684
|
const outputTokens = readNonNegativeInteger(usage.output_tokens ?? usage.outputTokens);
|
|
3657
3685
|
const reasoningOutputTokens = readNonNegativeInteger(usage.reasoning_output_tokens ?? usage.reasoningOutputTokens);
|
|
3658
3686
|
const totalTokens = readNonNegativeInteger(usage.total_tokens ?? usage.totalTokens)
|
|
3659
|
-
?? ((inputTokens === null && cachedInputTokens === null && outputTokens === null && reasoningOutputTokens === null)
|
|
3687
|
+
?? ((inputTokens === null && cachedInputTokens === null && cacheCreationInputTokens === null && outputTokens === null && reasoningOutputTokens === null)
|
|
3660
3688
|
? null
|
|
3661
|
-
: ((inputTokens || 0) + (outputTokens || 0) + (reasoningOutputTokens || 0)));
|
|
3662
|
-
if (inputTokens === null && cachedInputTokens === null && outputTokens === null && reasoningOutputTokens === null && totalTokens === null) {
|
|
3689
|
+
: ((inputTokens || 0) + (cachedInputTokens || 0) + (cacheCreationInputTokens || 0) + (outputTokens || 0) + (reasoningOutputTokens || 0)));
|
|
3690
|
+
if (inputTokens === null && cachedInputTokens === null && cacheCreationInputTokens === null && outputTokens === null && reasoningOutputTokens === null && totalTokens === null) {
|
|
3663
3691
|
return null;
|
|
3664
3692
|
}
|
|
3665
3693
|
return {
|
|
3666
3694
|
inputTokens,
|
|
3667
3695
|
cachedInputTokens,
|
|
3696
|
+
cacheCreationInputTokens,
|
|
3668
3697
|
outputTokens,
|
|
3669
3698
|
reasoningOutputTokens,
|
|
3670
3699
|
totalTokens
|
|
@@ -3690,6 +3719,7 @@ function applyUsageTotalsToState(state, usageTotals) {
|
|
|
3690
3719
|
const pairs = [
|
|
3691
3720
|
['inputTokens', usageTotals.inputTokens],
|
|
3692
3721
|
['cachedInputTokens', usageTotals.cachedInputTokens],
|
|
3722
|
+
['cacheCreationInputTokens', usageTotals.cacheCreationInputTokens],
|
|
3693
3723
|
['outputTokens', usageTotals.outputTokens],
|
|
3694
3724
|
['reasoningOutputTokens', usageTotals.reasoningOutputTokens],
|
|
3695
3725
|
['totalTokens', usageTotals.totalTokens]
|
|
@@ -3940,12 +3970,13 @@ function parseCodexSessionSummary(filePath, options = {}) {
|
|
|
3940
3970
|
let contextWindow = 0;
|
|
3941
3971
|
let inputTokens = 0;
|
|
3942
3972
|
let cachedInputTokens = 0;
|
|
3973
|
+
let cacheCreationInputTokens = 0;
|
|
3943
3974
|
let outputTokens = 0;
|
|
3944
3975
|
let reasoningOutputTokens = 0;
|
|
3945
3976
|
let provider = 'codex';
|
|
3946
3977
|
let model = '';
|
|
3947
3978
|
const models = [];
|
|
3948
|
-
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, outputTokens, reasoningOutputTokens };
|
|
3979
|
+
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, cacheCreationInputTokens, outputTokens, reasoningOutputTokens };
|
|
3949
3980
|
const previewMessages = [];
|
|
3950
3981
|
|
|
3951
3982
|
for (const record of records) {
|
|
@@ -3958,6 +3989,7 @@ function parseCodexSessionSummary(filePath, options = {}) {
|
|
|
3958
3989
|
contextWindow = usageState.contextWindow || 0;
|
|
3959
3990
|
inputTokens = usageState.inputTokens || 0;
|
|
3960
3991
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
3992
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
3961
3993
|
outputTokens = usageState.outputTokens || 0;
|
|
3962
3994
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
3963
3995
|
|
|
@@ -3992,6 +4024,7 @@ function parseCodexSessionSummary(filePath, options = {}) {
|
|
|
3992
4024
|
contextWindow = usageState.contextWindow || 0;
|
|
3993
4025
|
inputTokens = usageState.inputTokens || 0;
|
|
3994
4026
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4027
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
3995
4028
|
outputTokens = usageState.outputTokens || 0;
|
|
3996
4029
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
3997
4030
|
provider = readExplicitSessionProviderFromRecord(record) || provider;
|
|
@@ -4051,6 +4084,7 @@ function parseCodexSessionSummary(filePath, options = {}) {
|
|
|
4051
4084
|
contextWindow,
|
|
4052
4085
|
inputTokens,
|
|
4053
4086
|
cachedInputTokens,
|
|
4087
|
+
cacheCreationInputTokens,
|
|
4054
4088
|
outputTokens,
|
|
4055
4089
|
reasoningOutputTokens,
|
|
4056
4090
|
__messageCountExact: isSessionSummaryMessageCountExact(stat, summaryReadBytes),
|
|
@@ -4087,12 +4121,13 @@ function parseClaudeSessionSummary(filePath, options = {}) {
|
|
|
4087
4121
|
let contextWindow = 0;
|
|
4088
4122
|
let inputTokens = 0;
|
|
4089
4123
|
let cachedInputTokens = 0;
|
|
4124
|
+
let cacheCreationInputTokens = 0;
|
|
4090
4125
|
let outputTokens = 0;
|
|
4091
4126
|
let reasoningOutputTokens = 0;
|
|
4092
4127
|
let provider = 'claude';
|
|
4093
4128
|
let model = '';
|
|
4094
4129
|
const models = [];
|
|
4095
|
-
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, outputTokens, reasoningOutputTokens };
|
|
4130
|
+
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, cacheCreationInputTokens, outputTokens, reasoningOutputTokens };
|
|
4096
4131
|
const previewMessages = [];
|
|
4097
4132
|
let createdAt = '';
|
|
4098
4133
|
let updatedAt = stat.mtime.toISOString();
|
|
@@ -4110,6 +4145,7 @@ function parseClaudeSessionSummary(filePath, options = {}) {
|
|
|
4110
4145
|
contextWindow = usageState.contextWindow || 0;
|
|
4111
4146
|
inputTokens = usageState.inputTokens || 0;
|
|
4112
4147
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4148
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
4113
4149
|
outputTokens = usageState.outputTokens || 0;
|
|
4114
4150
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
4115
4151
|
|
|
@@ -4143,6 +4179,7 @@ function parseClaudeSessionSummary(filePath, options = {}) {
|
|
|
4143
4179
|
contextWindow = usageState.contextWindow || 0;
|
|
4144
4180
|
inputTokens = usageState.inputTokens || 0;
|
|
4145
4181
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4182
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
4146
4183
|
outputTokens = usageState.outputTokens || 0;
|
|
4147
4184
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
4148
4185
|
provider = readExplicitSessionProviderFromRecord(record) || provider;
|
|
@@ -4201,6 +4238,7 @@ function parseClaudeSessionSummary(filePath, options = {}) {
|
|
|
4201
4238
|
contextWindow,
|
|
4202
4239
|
inputTokens,
|
|
4203
4240
|
cachedInputTokens,
|
|
4241
|
+
cacheCreationInputTokens,
|
|
4204
4242
|
outputTokens,
|
|
4205
4243
|
reasoningOutputTokens,
|
|
4206
4244
|
__messageCountExact: isSessionSummaryMessageCountExact(stat, summaryReadBytes),
|
|
@@ -4237,12 +4275,13 @@ function parseCodeBuddySessionSummary(filePath, options = {}) {
|
|
|
4237
4275
|
let contextWindow = 0;
|
|
4238
4276
|
let inputTokens = 0;
|
|
4239
4277
|
let cachedInputTokens = 0;
|
|
4278
|
+
let cacheCreationInputTokens = 0;
|
|
4240
4279
|
let outputTokens = 0;
|
|
4241
4280
|
let reasoningOutputTokens = 0;
|
|
4242
4281
|
let provider = 'codebuddy';
|
|
4243
4282
|
let model = '';
|
|
4244
4283
|
const models = [];
|
|
4245
|
-
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, outputTokens, reasoningOutputTokens };
|
|
4284
|
+
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, cacheCreationInputTokens, outputTokens, reasoningOutputTokens };
|
|
4246
4285
|
const previewMessages = [];
|
|
4247
4286
|
let createdAt = '';
|
|
4248
4287
|
let updatedAt = stat.mtime.toISOString();
|
|
@@ -4260,6 +4299,7 @@ function parseCodeBuddySessionSummary(filePath, options = {}) {
|
|
|
4260
4299
|
contextWindow = usageState.contextWindow || 0;
|
|
4261
4300
|
inputTokens = usageState.inputTokens || 0;
|
|
4262
4301
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4302
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
4263
4303
|
outputTokens = usageState.outputTokens || 0;
|
|
4264
4304
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
4265
4305
|
|
|
@@ -4298,6 +4338,7 @@ function parseCodeBuddySessionSummary(filePath, options = {}) {
|
|
|
4298
4338
|
contextWindow = usageState.contextWindow || 0;
|
|
4299
4339
|
inputTokens = usageState.inputTokens || 0;
|
|
4300
4340
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4341
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
4301
4342
|
outputTokens = usageState.outputTokens || 0;
|
|
4302
4343
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
4303
4344
|
provider = readExplicitSessionProviderFromRecord(record) || provider;
|
|
@@ -4358,6 +4399,7 @@ function parseCodeBuddySessionSummary(filePath, options = {}) {
|
|
|
4358
4399
|
contextWindow,
|
|
4359
4400
|
inputTokens,
|
|
4360
4401
|
cachedInputTokens,
|
|
4402
|
+
cacheCreationInputTokens,
|
|
4361
4403
|
outputTokens,
|
|
4362
4404
|
reasoningOutputTokens,
|
|
4363
4405
|
__messageCountExact: isSessionSummaryMessageCountExact(stat, summaryReadBytes),
|
|
@@ -4647,17 +4689,19 @@ function listClaudeSessions(limit, options = {}) {
|
|
|
4647
4689
|
let contextWindow = 0;
|
|
4648
4690
|
let inputTokens = 0;
|
|
4649
4691
|
let cachedInputTokens = 0;
|
|
4692
|
+
let cacheCreationInputTokens = 0;
|
|
4650
4693
|
let outputTokens = 0;
|
|
4651
4694
|
let reasoningOutputTokens = 0;
|
|
4652
4695
|
let model = typeof entry.model === 'string' ? entry.model.trim() : '';
|
|
4653
4696
|
const models = model ? [model] : [];
|
|
4654
4697
|
|
|
4655
|
-
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, outputTokens, reasoningOutputTokens };
|
|
4698
|
+
const usageState = { totalTokens, contextWindow, inputTokens, cachedInputTokens, cacheCreationInputTokens, outputTokens, reasoningOutputTokens };
|
|
4656
4699
|
applySessionUsageSummaryFromIndexEntry(usageState, entry);
|
|
4657
4700
|
totalTokens = usageState.totalTokens || 0;
|
|
4658
4701
|
contextWindow = usageState.contextWindow || 0;
|
|
4659
4702
|
inputTokens = usageState.inputTokens || 0;
|
|
4660
4703
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4704
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
4661
4705
|
outputTokens = usageState.outputTokens || 0;
|
|
4662
4706
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
4663
4707
|
|
|
@@ -4688,6 +4732,7 @@ function listClaudeSessions(limit, options = {}) {
|
|
|
4688
4732
|
contextWindow = usageState.contextWindow || 0;
|
|
4689
4733
|
inputTokens = usageState.inputTokens || 0;
|
|
4690
4734
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4735
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
4691
4736
|
outputTokens = usageState.outputTokens || 0;
|
|
4692
4737
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
4693
4738
|
const filteredQuickMessages = removeLeadingSystemMessage(quickMessages);
|
|
@@ -4712,6 +4757,7 @@ function listClaudeSessions(limit, options = {}) {
|
|
|
4712
4757
|
contextWindow = usageState.contextWindow || 0;
|
|
4713
4758
|
inputTokens = usageState.inputTokens || 0;
|
|
4714
4759
|
cachedInputTokens = usageState.cachedInputTokens || 0;
|
|
4760
|
+
cacheCreationInputTokens = usageState.cacheCreationInputTokens || 0;
|
|
4715
4761
|
outputTokens = usageState.outputTokens || 0;
|
|
4716
4762
|
reasoningOutputTokens = usageState.reasoningOutputTokens || 0;
|
|
4717
4763
|
|
|
@@ -4735,6 +4781,7 @@ function listClaudeSessions(limit, options = {}) {
|
|
|
4735
4781
|
contextWindow,
|
|
4736
4782
|
inputTokens,
|
|
4737
4783
|
cachedInputTokens,
|
|
4784
|
+
cacheCreationInputTokens,
|
|
4738
4785
|
outputTokens,
|
|
4739
4786
|
reasoningOutputTokens,
|
|
4740
4787
|
model,
|
|
@@ -10017,6 +10064,7 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
|
|
|
10017
10064
|
result = {
|
|
10018
10065
|
provider: config.model_provider || '未设置',
|
|
10019
10066
|
model: config.model || '未设置',
|
|
10067
|
+
currentModels: readCurrentModels(),
|
|
10020
10068
|
serviceTier,
|
|
10021
10069
|
modelReasoningEffort,
|
|
10022
10070
|
modelContextWindow,
|
|
@@ -10133,6 +10181,10 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
|
|
|
10133
10181
|
break;
|
|
10134
10182
|
case 'apply-claude-md-file':
|
|
10135
10183
|
result = applyClaudeMdFile(params || {});
|
|
10184
|
+
if (result && !result.error) {
|
|
10185
|
+
const mdTarget = (params && params.targetPath) ? String(params.targetPath) : 'CLAUDE.md';
|
|
10186
|
+
notifyWebhook('claude-md-edit', 'CLAUDE.md modified: ' + mdTarget, { targetPath: mdTarget }).catch(function () {});
|
|
10187
|
+
}
|
|
10136
10188
|
break;
|
|
10137
10189
|
case 'preview-agents-diff':
|
|
10138
10190
|
result = buildAgentsDiff(params || {});
|
|
@@ -10208,7 +10260,32 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
|
|
|
10208
10260
|
break;
|
|
10209
10261
|
case 'apply-claude-config':
|
|
10210
10262
|
result = applyToClaudeSettings(params.config);
|
|
10263
|
+
if (result && !result.error) {
|
|
10264
|
+
const cfgName = (params && params.config && typeof params.config.name === 'string') ? params.config.name : '';
|
|
10265
|
+
const cfgFrom = (params && typeof params.previousName === 'string') ? params.previousName : '';
|
|
10266
|
+
const summary = cfgFrom
|
|
10267
|
+
? ('Provider switched: ' + cfgFrom + ' -> ' + cfgName)
|
|
10268
|
+
: ('Provider applied: ' + cfgName);
|
|
10269
|
+
notifyWebhook('provider-switch', summary, { name: cfgName, previousName: cfgFrom }).catch(function () {});
|
|
10270
|
+
}
|
|
10211
10271
|
break;
|
|
10272
|
+
case 'get-webhook-config':
|
|
10273
|
+
result = loadWebhookConfig();
|
|
10274
|
+
break;
|
|
10275
|
+
case 'set-webhook-config':
|
|
10276
|
+
result = saveWebhookConfig(params && params.config ? params.config : {});
|
|
10277
|
+
break;
|
|
10278
|
+
case 'test-webhook': {
|
|
10279
|
+
const overrideCfg = params && params.config ? params.config : null;
|
|
10280
|
+
const probe = await notifyWebhook(
|
|
10281
|
+
'provider-switch',
|
|
10282
|
+
'codexmate webhook test ping',
|
|
10283
|
+
{ test: true },
|
|
10284
|
+
overrideCfg ? { config: overrideCfg } : {}
|
|
10285
|
+
);
|
|
10286
|
+
result = probe;
|
|
10287
|
+
break;
|
|
10288
|
+
}
|
|
10212
10289
|
case 'export-claude-share':
|
|
10213
10290
|
result = buildClaudeSharePayload(params && params.config ? params.config : {});
|
|
10214
10291
|
break;
|
|
@@ -12360,35 +12437,47 @@ function buildMcpProviderListPayload() {
|
|
|
12360
12437
|
configReady: !listConfigResult.isVirtual,
|
|
12361
12438
|
configErrorType: listConfigResult.errorType || '',
|
|
12362
12439
|
configNotice: listConfigResult.reason || '',
|
|
12363
|
-
providers: Object.entries(providers).map(([name, p]) =>
|
|
12364
|
-
|
|
12365
|
-
|
|
12366
|
-
|
|
12367
|
-
|
|
12368
|
-
|
|
12369
|
-
|
|
12370
|
-
|
|
12371
|
-
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
|
|
12376
|
-
|
|
12377
|
-
|
|
12378
|
-
|
|
12379
|
-
|
|
12380
|
-
|
|
12381
|
-
|
|
12382
|
-
|
|
12383
|
-
|
|
12384
|
-
|
|
12385
|
-
|
|
12386
|
-
|
|
12387
|
-
|
|
12388
|
-
|
|
12389
|
-
|
|
12390
|
-
|
|
12391
|
-
|
|
12440
|
+
providers: Object.entries(providers).map(([name, p]) => {
|
|
12441
|
+
const bridge = typeof p.codexmate_bridge === 'string' ? p.codexmate_bridge.trim() : '';
|
|
12442
|
+
let upstreamUrl = '';
|
|
12443
|
+
if (bridge === 'openai') {
|
|
12444
|
+
const upstream = resolveOpenaiBridgeUpstream(OPENAI_BRIDGE_SETTINGS_FILE, name);
|
|
12445
|
+
if (upstream && !upstream.error && typeof upstream.baseUrl === 'string') {
|
|
12446
|
+
upstreamUrl = upstream.baseUrl.trim();
|
|
12447
|
+
}
|
|
12448
|
+
}
|
|
12449
|
+
return {
|
|
12450
|
+
name,
|
|
12451
|
+
url: p.base_url || '',
|
|
12452
|
+
upstreamUrl,
|
|
12453
|
+
codexmate_bridge: bridge,
|
|
12454
|
+
key: maskKey(p.preferred_auth_method || ''),
|
|
12455
|
+
hasKey: !!(p.preferred_auth_method && p.preferred_auth_method.trim()),
|
|
12456
|
+
models: Array.isArray(p.models)
|
|
12457
|
+
? p.models
|
|
12458
|
+
.filter((model) => model && typeof model === 'object' && !Array.isArray(model))
|
|
12459
|
+
.map((model) => ({
|
|
12460
|
+
id: typeof model.id === 'string' ? model.id : '',
|
|
12461
|
+
name: typeof model.name === 'string' ? model.name : '',
|
|
12462
|
+
cost: model.cost && typeof model.cost === 'object' && !Array.isArray(model.cost)
|
|
12463
|
+
? {
|
|
12464
|
+
input: model.cost.input,
|
|
12465
|
+
output: model.cost.output,
|
|
12466
|
+
cacheRead: model.cost.cacheRead,
|
|
12467
|
+
cacheWrite: model.cost.cacheWrite
|
|
12468
|
+
}
|
|
12469
|
+
: null,
|
|
12470
|
+
contextWindow: model.contextWindow,
|
|
12471
|
+
maxTokens: model.maxTokens
|
|
12472
|
+
}))
|
|
12473
|
+
.filter((model) => model.id)
|
|
12474
|
+
: [],
|
|
12475
|
+
current: name === current,
|
|
12476
|
+
readOnly: isBuiltinManagedProvider(name),
|
|
12477
|
+
nonDeletable: isNonDeletableProvider(name),
|
|
12478
|
+
nonEditable: isNonEditableProvider(name)
|
|
12479
|
+
};
|
|
12480
|
+
})
|
|
12392
12481
|
};
|
|
12393
12482
|
}
|
|
12394
12483
|
|
package/lib/cli-models-utils.js
CHANGED
|
@@ -48,37 +48,86 @@ const ANTHROPIC_CLAUDE_MODELS = Object.freeze([
|
|
|
48
48
|
'claude-3-haiku'
|
|
49
49
|
]);
|
|
50
50
|
|
|
51
|
+
const DEEPSEEK_CLAUDE_COMPAT_MODELS = Object.freeze([
|
|
52
|
+
'DeepSeek-V3.2',
|
|
53
|
+
'DeepSeek-V3',
|
|
54
|
+
'DeepSeek-R1',
|
|
55
|
+
'deepseek-chat'
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
const QWEN_CLAUDE_COMPAT_MODELS = Object.freeze([
|
|
59
|
+
'qwen3-coder',
|
|
60
|
+
'qwen-max',
|
|
61
|
+
'qwen-plus',
|
|
62
|
+
'qwen-turbo'
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
const MODELSCOPE_CLAUDE_COMPAT_MODELS = Object.freeze([
|
|
66
|
+
'ZhipuAI/GLM-5'
|
|
67
|
+
]);
|
|
68
|
+
|
|
51
69
|
function normalizeModelCatalogId(value) {
|
|
52
70
|
return typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
53
71
|
}
|
|
54
72
|
|
|
55
|
-
function
|
|
73
|
+
function hasPathSegment(baseUrl, segment) {
|
|
56
74
|
const normalized = normalizeBaseUrl(baseUrl);
|
|
57
75
|
if (!normalized) return false;
|
|
58
76
|
try {
|
|
59
77
|
const parsed = new URL(normalized);
|
|
60
|
-
const host = String(parsed.hostname || '').toLowerCase();
|
|
61
78
|
const pathname = String(parsed.pathname || '').toLowerCase();
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
return isBigModelHost && hasAnthropicSegment;
|
|
79
|
+
const escaped = String(segment || '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&').toLowerCase();
|
|
80
|
+
return new RegExp(`(^|/)${escaped}(/|$)`).test(pathname);
|
|
65
81
|
} catch (_) {
|
|
66
82
|
return false;
|
|
67
83
|
}
|
|
68
84
|
}
|
|
69
85
|
|
|
70
|
-
function
|
|
86
|
+
function getBaseUrlHost(baseUrl) {
|
|
71
87
|
const normalized = normalizeBaseUrl(baseUrl);
|
|
72
|
-
if (!normalized) return
|
|
88
|
+
if (!normalized) return '';
|
|
73
89
|
try {
|
|
74
90
|
const parsed = new URL(normalized);
|
|
75
|
-
|
|
76
|
-
return host === 'api.anthropic.com' || host.endsWith('.anthropic.com');
|
|
91
|
+
return String(parsed.hostname || '').toLowerCase();
|
|
77
92
|
} catch (_) {
|
|
78
|
-
return
|
|
93
|
+
return '';
|
|
79
94
|
}
|
|
80
95
|
}
|
|
81
96
|
|
|
97
|
+
function isHostOrSubdomain(host, domain) {
|
|
98
|
+
return host === domain || host.endsWith(`.${domain}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function isBigModelClaudeCompatibleBaseUrl(baseUrl) {
|
|
102
|
+
const host = getBaseUrlHost(baseUrl);
|
|
103
|
+
return isHostOrSubdomain(host, 'bigmodel.cn') && hasPathSegment(baseUrl, 'anthropic');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function isAnthropicBaseUrl(baseUrl) {
|
|
107
|
+
const host = getBaseUrlHost(baseUrl);
|
|
108
|
+
return isHostOrSubdomain(host, 'anthropic.com');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function isDeepSeekClaudeCompatibleBaseUrl(baseUrl) {
|
|
112
|
+
const host = getBaseUrlHost(baseUrl);
|
|
113
|
+
return isHostOrSubdomain(host, 'deepseek.com') && hasPathSegment(baseUrl, 'anthropic');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function isQwenClaudeCompatibleBaseUrl(baseUrl) {
|
|
117
|
+
const host = getBaseUrlHost(baseUrl);
|
|
118
|
+
return isHostOrSubdomain(host, 'dashscope.aliyuncs.com') && hasPathSegment(baseUrl, 'anthropic');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function isZaiClaudeCompatibleBaseUrl(baseUrl) {
|
|
122
|
+
const host = getBaseUrlHost(baseUrl);
|
|
123
|
+
return isHostOrSubdomain(host, 'z.ai') && hasPathSegment(baseUrl, 'anthropic');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function isModelScopeBaseUrl(baseUrl) {
|
|
127
|
+
const host = getBaseUrlHost(baseUrl);
|
|
128
|
+
return isHostOrSubdomain(host, 'modelscope.cn');
|
|
129
|
+
}
|
|
130
|
+
|
|
82
131
|
function getSupplementalModelsForBaseUrl(baseUrl) {
|
|
83
132
|
if (isBigModelClaudeCompatibleBaseUrl(baseUrl)) {
|
|
84
133
|
return [...BIGMODEL_CLAUDE_COMPAT_MODELS];
|
|
@@ -86,6 +135,18 @@ function getSupplementalModelsForBaseUrl(baseUrl) {
|
|
|
86
135
|
if (isAnthropicBaseUrl(baseUrl)) {
|
|
87
136
|
return [...ANTHROPIC_CLAUDE_MODELS];
|
|
88
137
|
}
|
|
138
|
+
if (isDeepSeekClaudeCompatibleBaseUrl(baseUrl)) {
|
|
139
|
+
return [...DEEPSEEK_CLAUDE_COMPAT_MODELS];
|
|
140
|
+
}
|
|
141
|
+
if (isQwenClaudeCompatibleBaseUrl(baseUrl)) {
|
|
142
|
+
return [...QWEN_CLAUDE_COMPAT_MODELS];
|
|
143
|
+
}
|
|
144
|
+
if (isZaiClaudeCompatibleBaseUrl(baseUrl)) {
|
|
145
|
+
return [...BIGMODEL_CLAUDE_COMPAT_MODELS];
|
|
146
|
+
}
|
|
147
|
+
if (isModelScopeBaseUrl(baseUrl)) {
|
|
148
|
+
return [...MODELSCOPE_CLAUDE_COMPAT_MODELS];
|
|
149
|
+
}
|
|
89
150
|
return [];
|
|
90
151
|
}
|
|
91
152
|
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const http = require('http');
|
|
4
|
+
const https = require('https');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
const ALLOWED_EVENTS = ['provider-switch', 'claude-md-edit'];
|
|
8
|
+
const DEFAULT_TIMEOUT_MS = 5000;
|
|
9
|
+
|
|
10
|
+
function defaultConfigPath() {
|
|
11
|
+
return path.join(os.homedir(), '.codex', 'codexmate-webhook.json');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function normalizeConfig(cfg) {
|
|
15
|
+
const out = { enabled: false, url: '', events: ALLOWED_EVENTS.slice() };
|
|
16
|
+
if (!cfg || typeof cfg !== 'object') return out;
|
|
17
|
+
out.enabled = !!cfg.enabled;
|
|
18
|
+
out.url = typeof cfg.url === 'string' ? cfg.url.trim() : '';
|
|
19
|
+
if (Array.isArray(cfg.events)) {
|
|
20
|
+
const filtered = cfg.events.filter(function (e) { return ALLOWED_EVENTS.indexOf(e) !== -1; });
|
|
21
|
+
out.events = filtered.length ? filtered : ALLOWED_EVENTS.slice();
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function loadWebhookConfig(filePath) {
|
|
27
|
+
const target = filePath || defaultConfigPath();
|
|
28
|
+
try {
|
|
29
|
+
if (!fs.existsSync(target)) {
|
|
30
|
+
return normalizeConfig({});
|
|
31
|
+
}
|
|
32
|
+
const raw = fs.readFileSync(target, 'utf-8');
|
|
33
|
+
return normalizeConfig(JSON.parse(raw));
|
|
34
|
+
} catch (_) {
|
|
35
|
+
return normalizeConfig({});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function saveWebhookConfig(cfg, filePath) {
|
|
40
|
+
const target = filePath || defaultConfigPath();
|
|
41
|
+
const normalized = normalizeConfig(cfg);
|
|
42
|
+
try {
|
|
43
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
44
|
+
} catch (_) {}
|
|
45
|
+
fs.writeFileSync(target, JSON.stringify(normalized, null, 2), 'utf-8');
|
|
46
|
+
return normalized;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function postJson(targetUrl, payload, timeoutMs) {
|
|
50
|
+
return new Promise(function (resolve) {
|
|
51
|
+
let parsed;
|
|
52
|
+
try {
|
|
53
|
+
parsed = new URL(targetUrl);
|
|
54
|
+
} catch (_) {
|
|
55
|
+
resolve({ ok: false, error: 'invalid-url' });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const transport = parsed.protocol === 'https:' ? https : http;
|
|
59
|
+
const body = JSON.stringify(payload || {});
|
|
60
|
+
let req;
|
|
61
|
+
try {
|
|
62
|
+
req = transport.request({
|
|
63
|
+
method: 'POST',
|
|
64
|
+
protocol: parsed.protocol,
|
|
65
|
+
hostname: parsed.hostname,
|
|
66
|
+
port: parsed.port || (parsed.protocol === 'https:' ? 443 : 80),
|
|
67
|
+
path: (parsed.pathname || '/') + (parsed.search || ''),
|
|
68
|
+
headers: {
|
|
69
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
70
|
+
'Content-Length': Buffer.byteLength(body, 'utf-8'),
|
|
71
|
+
'User-Agent': 'codexmate-webhook/1'
|
|
72
|
+
}
|
|
73
|
+
}, function (res) {
|
|
74
|
+
let raw = '';
|
|
75
|
+
res.on('data', function (chunk) {
|
|
76
|
+
if (raw.length < 1024) raw += chunk.toString('utf-8');
|
|
77
|
+
});
|
|
78
|
+
res.on('end', function () {
|
|
79
|
+
const status = res.statusCode || 0;
|
|
80
|
+
resolve({ ok: status >= 200 && status < 300, status: status, body: raw.slice(0, 200) });
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
} catch (e) {
|
|
84
|
+
resolve({ ok: false, error: e && e.message ? e.message : String(e) });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const wait = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : DEFAULT_TIMEOUT_MS;
|
|
88
|
+
req.setTimeout(wait, function () { req.destroy(new Error('timeout')); });
|
|
89
|
+
req.on('error', function (err) { resolve({ ok: false, error: err && err.message ? err.message : String(err) }); });
|
|
90
|
+
req.write(body);
|
|
91
|
+
req.end();
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function buildPayload(event, summary, details) {
|
|
96
|
+
return {
|
|
97
|
+
event: String(event || ''),
|
|
98
|
+
summary: String(summary || ''),
|
|
99
|
+
operator: process.env.USER || process.env.USERNAME || (os.userInfo && os.userInfo().username) || '',
|
|
100
|
+
timestamp: new Date().toISOString(),
|
|
101
|
+
details: details && typeof details === 'object' ? details : {}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function notifyWebhook(event, summary, details, options) {
|
|
106
|
+
const opts = options || {};
|
|
107
|
+
const cfg = opts.config ? normalizeConfig(opts.config) : loadWebhookConfig(opts.filePath);
|
|
108
|
+
if (!cfg.enabled || !cfg.url) {
|
|
109
|
+
return Promise.resolve({ ok: false, skipped: true, reason: 'disabled' });
|
|
110
|
+
}
|
|
111
|
+
if (cfg.events.indexOf(event) === -1) {
|
|
112
|
+
return Promise.resolve({ ok: false, skipped: true, reason: 'event-filtered' });
|
|
113
|
+
}
|
|
114
|
+
return postJson(cfg.url, buildPayload(event, summary, details), opts.timeoutMs);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
module.exports = {
|
|
118
|
+
ALLOWED_EVENTS,
|
|
119
|
+
defaultConfigPath,
|
|
120
|
+
normalizeConfig,
|
|
121
|
+
loadWebhookConfig,
|
|
122
|
+
saveWebhookConfig,
|
|
123
|
+
notifyWebhook,
|
|
124
|
+
buildPayload,
|
|
125
|
+
postJson
|
|
126
|
+
};
|