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/package.json
CHANGED
|
@@ -1,74 +1,76 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "codexmate",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Codex/Claude Code/OpenClaw 配置、会话与任务编排 CLI + Web 工具",
|
|
5
|
-
"main": "cli.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
"codexmate": "./cli.js"
|
|
8
|
-
},
|
|
9
|
-
"files": [
|
|
10
|
-
"cli.js",
|
|
11
|
-
"cli/",
|
|
12
|
-
"plugins/",
|
|
13
|
-
"web-ui.html",
|
|
14
|
-
"lib/",
|
|
15
|
-
"web-ui/",
|
|
16
|
-
"doc/",
|
|
17
|
-
"README.md",
|
|
18
|
-
"README.zh.md",
|
|
19
|
-
"LICENSE"
|
|
20
|
-
],
|
|
21
|
-
"exports": {
|
|
22
|
-
".": "./cli.js",
|
|
23
|
-
"./lib/*": "./lib/*.js",
|
|
24
|
-
"./web-ui/*": "./web-ui/*",
|
|
25
|
-
"./res/*": "./web-ui/res/*"
|
|
26
|
-
},
|
|
27
|
-
"scripts": {
|
|
28
|
-
"dev": "node cli.js run",
|
|
29
|
-
"start": "node cli.js",
|
|
30
|
-
"reset": "node tools/dev/reset-main.js",
|
|
31
|
-
"release:npm": "node tools/release/publish-npm.js",
|
|
32
|
-
"docs:dev": "node ./node_modules/vitepress/dist/node/cli.js dev site",
|
|
33
|
-
"docs:build": "node ./node_modules/vitepress/dist/node/cli.js build site",
|
|
34
|
-
"docs:preview": "node ./node_modules/vitepress/dist/node/cli.js preview site",
|
|
35
|
-
"ci:install": "node tools/ci/run-check.js install",
|
|
36
|
-
"ci:lint": "node tools/ci/run-check.js lint",
|
|
37
|
-
"ci:test": "node tools/ci/run-check.js test",
|
|
38
|
-
"lint": "node tools/dev/lint.js",
|
|
39
|
-
"test": "npm run test:unit && npm run test:e2e",
|
|
40
|
-
"test:ci": "node tools/ci/run-check.js all",
|
|
41
|
-
"test:unit": "node tests/unit/run.mjs",
|
|
42
|
-
"test:e2e": "node tests/e2e/run.js",
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
"
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "codexmate",
|
|
3
|
+
"version": "0.0.29",
|
|
4
|
+
"description": "Codex/Claude Code/OpenClaw 配置、会话与任务编排 CLI + Web 工具",
|
|
5
|
+
"main": "cli.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"codexmate": "./cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"cli.js",
|
|
11
|
+
"cli/",
|
|
12
|
+
"plugins/",
|
|
13
|
+
"web-ui.html",
|
|
14
|
+
"lib/",
|
|
15
|
+
"web-ui/",
|
|
16
|
+
"doc/",
|
|
17
|
+
"README.md",
|
|
18
|
+
"README.zh.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"exports": {
|
|
22
|
+
".": "./cli.js",
|
|
23
|
+
"./lib/*": "./lib/*.js",
|
|
24
|
+
"./web-ui/*": "./web-ui/*",
|
|
25
|
+
"./res/*": "./web-ui/res/*"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"dev": "node cli.js run",
|
|
29
|
+
"start": "node cli.js",
|
|
30
|
+
"reset": "node tools/dev/reset-main.js",
|
|
31
|
+
"release:npm": "node tools/release/publish-npm.js",
|
|
32
|
+
"docs:dev": "node ./node_modules/vitepress/dist/node/cli.js dev site",
|
|
33
|
+
"docs:build": "node ./node_modules/vitepress/dist/node/cli.js build site",
|
|
34
|
+
"docs:preview": "node ./node_modules/vitepress/dist/node/cli.js preview site",
|
|
35
|
+
"ci:install": "node tools/ci/run-check.js install",
|
|
36
|
+
"ci:lint": "node tools/ci/run-check.js lint",
|
|
37
|
+
"ci:test": "node tools/ci/run-check.js test",
|
|
38
|
+
"lint": "node tools/dev/lint.js",
|
|
39
|
+
"test": "npm run test:unit && npm run test:e2e",
|
|
40
|
+
"test:ci": "node tools/ci/run-check.js all",
|
|
41
|
+
"test:unit": "node tests/unit/run.mjs",
|
|
42
|
+
"test:e2e": "node tests/e2e/run.js",
|
|
43
|
+
"setup:git": "git remote set-url origin https://github.com/SakuraByteCore/codexmate.git && gh auth setup-git",
|
|
44
|
+
"reset:dev": "node tools/dev/reset-and-dev.js",
|
|
45
|
+
"pretest": "node tools/ci/ensure-test-deps.js"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@iarna/toml": "^2.2.5",
|
|
49
|
+
"json5": "^2.2.3",
|
|
50
|
+
"yauzl": "^3.2.1",
|
|
51
|
+
"zip-lib": "^1.2.1"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=14"
|
|
55
|
+
},
|
|
56
|
+
"keywords": [
|
|
57
|
+
"codex",
|
|
58
|
+
"claude",
|
|
59
|
+
"claude-code",
|
|
60
|
+
"openclaw",
|
|
61
|
+
"config",
|
|
62
|
+
"session",
|
|
63
|
+
"task-orchestration",
|
|
64
|
+
"workflow",
|
|
65
|
+
"web-ui",
|
|
66
|
+
"provider",
|
|
67
|
+
"ai",
|
|
68
|
+
"llm",
|
|
69
|
+
"cli"
|
|
70
|
+
],
|
|
71
|
+
"author": "ymkiux",
|
|
72
|
+
"license": "Apache-2.0",
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"vitepress": "^1.6.4"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -98,7 +98,7 @@ function renderTemplate(templateText, values = {}) {
|
|
|
98
98
|
const name = String(key || '').trim();
|
|
99
99
|
if (!name) return '';
|
|
100
100
|
const value = map[name];
|
|
101
|
-
return value == null
|
|
101
|
+
return value == null || String(value).trim() === '' ? _whole : String(value);
|
|
102
102
|
});
|
|
103
103
|
}
|
|
104
104
|
|
|
@@ -358,72 +358,6 @@ export function createPluginsMethods() {
|
|
|
358
358
|
this.promptTemplateVarValuesRaw = {};
|
|
359
359
|
},
|
|
360
360
|
|
|
361
|
-
addPromptTemplateVariable() {
|
|
362
|
-
const draft = normalizePromptTemplateDraft(this.promptTemplateDraftRaw);
|
|
363
|
-
if (!draft || !draft.id) return;
|
|
364
|
-
if (draft.isBuiltin) {
|
|
365
|
-
this.showMessage(typeof this.t === 'function' ? this.t('toast.templates.builtinNotEditable') : 'Built-in templates are not editable', 'error');
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
this.promptTemplateVarDraftName = 'var';
|
|
369
|
-
this.promptTemplateVarDraftError = '';
|
|
370
|
-
this.showPromptTemplateVarModal = true;
|
|
371
|
-
if (typeof this.$nextTick === 'function') {
|
|
372
|
-
this.$nextTick(() => {
|
|
373
|
-
const input = this.$refs && this.$refs.promptTemplateVarNameInput
|
|
374
|
-
? this.$refs.promptTemplateVarNameInput
|
|
375
|
-
: null;
|
|
376
|
-
if (input && typeof input.focus === 'function') input.focus();
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
},
|
|
380
|
-
|
|
381
|
-
closePromptTemplateVarModal() {
|
|
382
|
-
this.showPromptTemplateVarModal = false;
|
|
383
|
-
this.promptTemplateVarDraftError = '';
|
|
384
|
-
},
|
|
385
|
-
|
|
386
|
-
confirmAddPromptTemplateVariable() {
|
|
387
|
-
const draft = normalizePromptTemplateDraft(this.promptTemplateDraftRaw);
|
|
388
|
-
if (!draft || !draft.id) return;
|
|
389
|
-
if (draft.isBuiltin) {
|
|
390
|
-
this.promptTemplateVarDraftError = typeof this.t === 'function'
|
|
391
|
-
? this.t('toast.templates.builtinNotEditable')
|
|
392
|
-
: 'Built-in templates are not editable';
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
const key = typeof this.promptTemplateVarDraftName === 'string'
|
|
396
|
-
? this.promptTemplateVarDraftName.trim()
|
|
397
|
-
: '';
|
|
398
|
-
if (!key) {
|
|
399
|
-
this.promptTemplateVarDraftError = typeof this.t === 'function'
|
|
400
|
-
? this.t('toast.templates.varNameRequired')
|
|
401
|
-
: 'Variable name is required';
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
if (!/^[a-zA-Z0-9_.-]+$/.test(key)) {
|
|
405
|
-
this.promptTemplateVarDraftError = typeof this.t === 'function'
|
|
406
|
-
? this.t('toast.templates.varNameInvalid')
|
|
407
|
-
: 'Variable name may only contain letters, numbers, underscore, dash, dot';
|
|
408
|
-
return;
|
|
409
|
-
}
|
|
410
|
-
const placeholder = `{{${key}}}`;
|
|
411
|
-
const current = typeof draft.template === 'string' ? draft.template : '';
|
|
412
|
-
if (current.includes(placeholder)) {
|
|
413
|
-
this.promptTemplateVarDraftError = typeof this.t === 'function'
|
|
414
|
-
? this.t('toast.templates.varExists')
|
|
415
|
-
: 'Variable already exists';
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
const nextText = current && !current.endsWith('\n')
|
|
419
|
-
? `${current}\n${placeholder}\n`
|
|
420
|
-
: `${current}${placeholder}\n`;
|
|
421
|
-
this.promptTemplateDraftRaw = { ...draft, template: nextText };
|
|
422
|
-
this.showPromptTemplateVarModal = false;
|
|
423
|
-
this.promptTemplateVarDraftError = '';
|
|
424
|
-
this.showMessage(typeof this.t === 'function' ? this.t('toast.templates.varAdded') : 'Variable added', 'success');
|
|
425
|
-
},
|
|
426
|
-
|
|
427
361
|
setPromptVariableValue(name, value) {
|
|
428
362
|
const key = typeof name === 'string' ? name.trim() : '';
|
|
429
363
|
if (!key) return;
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import { buildBuiltinCommentPolishTemplate } from './comment-polish/index.mjs';
|
|
8
8
|
import { buildBuiltinRuleAckTemplate } from './rule-ack/index.mjs';
|
|
9
9
|
|
|
10
|
+
|
|
10
11
|
function ensureBuiltinTemplates(rawList, builtins) {
|
|
11
12
|
const list = Array.isArray(rawList) ? rawList.filter(Boolean) : [];
|
|
12
13
|
const builtinList = Array.isArray(builtins) ? builtins.filter(Boolean) : [];
|
package/web-ui/app.js
CHANGED
|
@@ -34,6 +34,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
34
34
|
configMode: 'codex',
|
|
35
35
|
currentProvider: '',
|
|
36
36
|
currentModel: '',
|
|
37
|
+
currentModels: {},
|
|
37
38
|
serviceTier: 'fast',
|
|
38
39
|
modelReasoningEffort: 'medium',
|
|
39
40
|
modelContextWindowInput: String(DEFAULT_MODEL_CONTEXT_WINDOW),
|
|
@@ -81,9 +82,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
81
82
|
promptComposerPickerKeyword: '',
|
|
82
83
|
promptComposerSelectedTemplateId: '',
|
|
83
84
|
promptComposerVarValuesRaw: {},
|
|
84
|
-
showPromptTemplateVarModal: false,
|
|
85
|
-
promptTemplateVarDraftName: '',
|
|
86
|
-
promptTemplateVarDraftError: '',
|
|
87
85
|
showConfirmDialog: false,
|
|
88
86
|
confirmDialogTitle: '',
|
|
89
87
|
confirmDialogMessage: '',
|
|
@@ -174,7 +172,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
174
172
|
sessionRoleFilter: 'all',
|
|
175
173
|
sessionTimePreset: 'all',
|
|
176
174
|
sessionSortMode: 'time',
|
|
177
|
-
sessionResumeWithYolo: true,
|
|
178
175
|
sessionPathOptions: [],
|
|
179
176
|
sessionPathOptionsLoading: false,
|
|
180
177
|
sessionPathOptionsMap: {
|
|
@@ -258,7 +255,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
258
255
|
installRegistryPreset: 'default',
|
|
259
256
|
installRegistryCustom: '',
|
|
260
257
|
installStatusTargets: null,
|
|
261
|
-
newProvider: { name: '', url: '', key: '', useTransform: false },
|
|
258
|
+
newProvider: { name: '', url: '', key: '', useTransform: false, _suggestedModel: '' },
|
|
262
259
|
resetConfigLoading: false,
|
|
263
260
|
editingProvider: { name: '', url: '', key: '', readOnly: false, nonEditable: false },
|
|
264
261
|
newModelName: '',
|
|
@@ -277,8 +274,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
277
274
|
newClaudeConfig: {
|
|
278
275
|
name: '',
|
|
279
276
|
apiKey: '',
|
|
280
|
-
baseUrl: '
|
|
281
|
-
model: '
|
|
277
|
+
baseUrl: '',
|
|
278
|
+
model: ''
|
|
282
279
|
},
|
|
283
280
|
currentOpenclawConfig: '',
|
|
284
281
|
openclawConfigs: {
|
|
@@ -345,7 +342,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
345
342
|
codexDownloadLoading: false,
|
|
346
343
|
codexDownloadProgress: 0,
|
|
347
344
|
codexDownloadTimer: null,
|
|
348
|
-
settingsTab: '
|
|
345
|
+
settingsTab: 'general',
|
|
349
346
|
sessionTrashEnabled: true,
|
|
350
347
|
sessionTrashItems: [],
|
|
351
348
|
sessionTrashVisibleCount: SESSION_TRASH_PAGE_SIZE,
|
|
@@ -401,7 +398,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
401
398
|
lastLoadedAt: '',
|
|
402
399
|
lastError: ''
|
|
403
400
|
},
|
|
404
|
-
_taskOrchestrationPollTimer: 0
|
|
401
|
+
_taskOrchestrationPollTimer: 0,
|
|
402
|
+
webhookConfig: { enabled: false, url: '', events: ['provider-switch', 'claude-md-edit'] },
|
|
403
|
+
webhookEventOptions: ['provider-switch', 'claude-md-edit'],
|
|
404
|
+
webhookSaving: false,
|
|
405
|
+
webhookTestResult: null,
|
|
406
|
+
webhookTesting: false,
|
|
405
407
|
};
|
|
406
408
|
},
|
|
407
409
|
|
|
@@ -409,6 +411,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
409
411
|
if (typeof this.initI18n === 'function') {
|
|
410
412
|
this.initI18n();
|
|
411
413
|
}
|
|
414
|
+
if (typeof this.loadWebhookSettings === 'function') {
|
|
415
|
+
this.loadWebhookSettings();
|
|
416
|
+
}
|
|
412
417
|
if (typeof this.t === 'function') {
|
|
413
418
|
this.confirmDialogConfirmText = this.t('confirm.ok');
|
|
414
419
|
this.confirmDialogCancelText = this.t('confirm.cancel');
|
|
@@ -417,7 +422,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
417
422
|
}
|
|
418
423
|
{
|
|
419
424
|
const NAV_STATE_STORAGE_KEY = 'codexmateNavState.v1';
|
|
420
|
-
const mainTabSet = new Set(['dashboard', 'config', 'sessions', 'usage', 'orchestration', 'market', 'plugins', 'docs', 'settings']);
|
|
425
|
+
const mainTabSet = new Set(['dashboard', 'config', 'sessions', 'usage', 'orchestration', 'market', 'plugins', 'docs', 'settings', 'trash']);
|
|
421
426
|
let restored = null;
|
|
422
427
|
try {
|
|
423
428
|
const raw = localStorage.getItem(NAV_STATE_STORAGE_KEY) || '';
|
|
@@ -431,6 +436,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
431
436
|
const nextConfigMode = restored && typeof restored.configMode === 'string'
|
|
432
437
|
? restored.configMode.trim().toLowerCase()
|
|
433
438
|
: '';
|
|
439
|
+
const nextSettingsTab = restored && typeof restored.settingsTab === 'string'
|
|
440
|
+
? restored.settingsTab.trim().toLowerCase()
|
|
441
|
+
: '';
|
|
434
442
|
let urlMainTab = '';
|
|
435
443
|
try {
|
|
436
444
|
const url = new URL(window.location.href);
|
|
@@ -443,6 +451,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
443
451
|
const resolvedMainTab = urlMainTab && mainTabSet.has(urlMainTab)
|
|
444
452
|
? urlMainTab
|
|
445
453
|
: nextMainTab;
|
|
454
|
+
if (nextSettingsTab && (nextSettingsTab === 'general' || nextSettingsTab === 'data')) {
|
|
455
|
+
this.settingsTab = nextSettingsTab;
|
|
456
|
+
}
|
|
446
457
|
if (nextConfigMode && typeof this.switchConfigMode === 'function') {
|
|
447
458
|
this.__navStateRestoring = true;
|
|
448
459
|
try {
|
|
@@ -469,12 +480,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
469
480
|
if (!this.taskOrchestrationTabEnabled && this.mainTab === 'orchestration') {
|
|
470
481
|
this.mainTab = 'config';
|
|
471
482
|
}
|
|
472
|
-
const savedSessionYolo = localStorage.getItem('codexmateSessionResumeYolo');
|
|
473
|
-
if (savedSessionYolo === '0' || savedSessionYolo === 'false') {
|
|
474
|
-
this.sessionResumeWithYolo = false;
|
|
475
|
-
} else if (savedSessionYolo === '1' || savedSessionYolo === 'true') {
|
|
476
|
-
this.sessionResumeWithYolo = true;
|
|
477
|
-
}
|
|
478
483
|
this.restoreSessionFilterCache();
|
|
479
484
|
this.restoreSessionPinnedMap();
|
|
480
485
|
this.shareCommandPrefix = this.normalizeShareCommandPrefix(localStorage.getItem('codexmateShareCommandPrefix'));
|
package/web-ui/index.html
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
<!-- @include ./partials/index/panel-orchestration.html -->
|
|
22
22
|
<!-- @include ./partials/index/panel-docs.html -->
|
|
23
23
|
<!-- @include ./partials/index/panel-settings.html -->
|
|
24
|
+
<!-- @include ./partials/index/panel-trash.html -->
|
|
24
25
|
<!-- @include ./partials/index/panel-market.html -->
|
|
25
26
|
<!-- @include ./partials/index/panel-plugins.html -->
|
|
26
27
|
<!-- @include ./partials/index/layout-footer.html -->
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// 仅供 web-ui 的 codex 模型选择器与新增 provider 模板按钮使用。
|
|
2
|
+
// 镜像 logic.claude.mjs 的派生方式,但 codex provider 元信息不带 wire_api,
|
|
3
|
+
// 所以 catalog 仅按 baseUrl 的 host/path 命中。
|
|
4
|
+
|
|
5
|
+
const DEFAULT_OPENAI_CODEX_CATALOG = Object.freeze([
|
|
6
|
+
'gpt-5-codex',
|
|
7
|
+
'gpt-5',
|
|
8
|
+
'gpt-5-mini',
|
|
9
|
+
'gpt-4.1',
|
|
10
|
+
'o4-mini',
|
|
11
|
+
'o3-mini'
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
const HOST_RULES = Object.freeze([
|
|
15
|
+
{ match: (u) => /api\.openai\.com/i.test(u), models: DEFAULT_OPENAI_CODEX_CATALOG },
|
|
16
|
+
{ match: (u) => /api\.deepseek\.com/i.test(u), models: ['deepseek-chat', 'deepseek-coder', 'deepseek-reasoner'] },
|
|
17
|
+
{ match: (u) => /dashscope\.aliyuncs\.com/i.test(u), models: ['qwen3-coder-plus', 'qwen3-coder-flash', 'qwen-max', 'qwen-plus'] },
|
|
18
|
+
{ match: (u) => /ark\..*volces\.com/i.test(u), models: ['doubao-seed-1-6-thinking', 'doubao-seed-1-6', 'doubao-1-5-pro-32k', 'doubao-pro-32k'] },
|
|
19
|
+
{ match: (u) => /open\.bigmodel\.cn/i.test(u), models: ['glm-4.6', 'glm-4.5', 'glm-4-plus', 'glm-coding'] },
|
|
20
|
+
{ match: (u) => /api\.moonshot\.cn|api\.kimi\.com/i.test(u), models: ['moonshot-v1-32k', 'moonshot-v1-128k', 'kimi-latest'] },
|
|
21
|
+
{ match: (u) => /api\.minimax/i.test(u), models: ['MiniMax-M2', 'abab6.5s-chat', 'abab6.5-chat'] },
|
|
22
|
+
{ match: (u) => /api-inference\.modelscope\.cn/i.test(u), models: ['Qwen/Qwen3-Coder-480B-A35B-Instruct', 'ZhipuAI/GLM-4.5'] },
|
|
23
|
+
{ match: (u) => /xiaomimimo\.com/i.test(u), models: ['mimo-v2-pro', 'mimo-v2'] },
|
|
24
|
+
{ match: (u) => /ai\.muapi\.cn/i.test(u), models: ['mimo-v2-pro'] }
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
function normalizeUrl(url) {
|
|
28
|
+
return typeof url === 'string' ? url.trim().toLowerCase() : '';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getCodexModelCatalogForProvider(provider) {
|
|
32
|
+
if (!provider || typeof provider !== 'object') return [];
|
|
33
|
+
const url = normalizeUrl(provider.url || provider.baseUrl || '');
|
|
34
|
+
const name = typeof provider.name === 'string' ? provider.name.toLowerCase() : '';
|
|
35
|
+
if (!url) {
|
|
36
|
+
if (/openai/.test(name)) return [...DEFAULT_OPENAI_CODEX_CATALOG];
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
for (const rule of HOST_RULES) {
|
|
40
|
+
if (rule.match(url)) return [...rule.models];
|
|
41
|
+
}
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 服务模板表:供面板上的预设按钮使用。
|
|
46
|
+
// model 字段为可选首选项(添加后由前端写入内存字典 currentModels[name])。
|
|
47
|
+
// useTransform=true 表示该服务需通过内建 OpenAI bridge 转发。
|
|
48
|
+
export const CODEX_PROVIDER_TEMPLATES = Object.freeze([
|
|
49
|
+
{
|
|
50
|
+
label: 'MuAPI',
|
|
51
|
+
name: 'muapi',
|
|
52
|
+
url: 'https://ai.muapi.cn/v1',
|
|
53
|
+
model: 'mimo-v2-pro',
|
|
54
|
+
useTransform: true
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
label: 'Telepub',
|
|
58
|
+
name: 'telepub',
|
|
59
|
+
url: 'https://voyage.prod.telepub.cn/voyage/api',
|
|
60
|
+
model: 'DeepSeek-V4-pro',
|
|
61
|
+
useTransform: true
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
label: 'AnyRouter',
|
|
65
|
+
name: 'anyrouter',
|
|
66
|
+
url: 'https://anyrouter.top/v1',
|
|
67
|
+
model: 'gpt-5.5'
|
|
68
|
+
}
|
|
69
|
+
]);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { getProviderDisplayUrl, checkIsTransformProvider } from './provider-url-display.mjs';
|
|
2
|
+
import { getCodexModelCatalogForProvider, CODEX_PROVIDER_TEMPLATES } from '../logic.codex.mjs';
|
|
1
3
|
export function createDashboardComputed() {
|
|
2
4
|
return {
|
|
3
5
|
agentsDiffHasChanges() {
|
|
@@ -29,6 +31,50 @@ export function createDashboardComputed() {
|
|
|
29
31
|
}
|
|
30
32
|
return list;
|
|
31
33
|
},
|
|
34
|
+
activeProviderModel() {
|
|
35
|
+
return (name) => {
|
|
36
|
+
const target = String(name || '').trim();
|
|
37
|
+
if (!target) return '';
|
|
38
|
+
const dict = this.currentModels && typeof this.currentModels === 'object' ? this.currentModels : {};
|
|
39
|
+
const fromDict = typeof dict[target] === 'string' ? dict[target].trim() : '';
|
|
40
|
+
if (fromDict) return fromDict;
|
|
41
|
+
const activeName = String(this.currentProvider || '').trim();
|
|
42
|
+
if (target === activeName) {
|
|
43
|
+
const top = typeof this.currentModel === 'string' ? this.currentModel.trim() : '';
|
|
44
|
+
if (top && top !== '未设置') return top;
|
|
45
|
+
}
|
|
46
|
+
return '';
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
codexModelOptions() {
|
|
50
|
+
const seen = new Set();
|
|
51
|
+
const out = [];
|
|
52
|
+
const push = (val) => {
|
|
53
|
+
const s = typeof val === 'string' ? val.trim() : '';
|
|
54
|
+
if (!s || seen.has(s)) return;
|
|
55
|
+
seen.add(s);
|
|
56
|
+
out.push(s);
|
|
57
|
+
};
|
|
58
|
+
const activeName = String(this.displayCurrentProvider || '').trim();
|
|
59
|
+
const current = typeof this.currentModel === 'string' ? this.currentModel.trim() : '';
|
|
60
|
+
if (current && current !== '未设置') push(current);
|
|
61
|
+
const dict = this.currentModels && typeof this.currentModels === 'object' ? this.currentModels : {};
|
|
62
|
+
if (activeName && typeof dict[activeName] === 'string') push(dict[activeName]);
|
|
63
|
+
const remote = Array.isArray(this.models) ? this.models : [];
|
|
64
|
+
for (const m of remote) push(m);
|
|
65
|
+
const list = Array.isArray(this.providersList) ? this.providersList : [];
|
|
66
|
+
const activeProvider = list.find((p) => p && p.name === activeName);
|
|
67
|
+
if (activeProvider) {
|
|
68
|
+
for (const m of getCodexModelCatalogForProvider(activeProvider)) push(m);
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
},
|
|
72
|
+
codexModelHasList() {
|
|
73
|
+
return this.codexModelOptions.length > 0;
|
|
74
|
+
},
|
|
75
|
+
codexProviderTemplates() {
|
|
76
|
+
return CODEX_PROVIDER_TEMPLATES;
|
|
77
|
+
},
|
|
32
78
|
displayCurrentProvider() {
|
|
33
79
|
const switching = String(this.providerSwitchDisplayTarget || '').trim();
|
|
34
80
|
if (switching) return switching;
|
|
@@ -39,6 +85,14 @@ export function createDashboardComputed() {
|
|
|
39
85
|
const list = Array.isArray(this.providersList) ? this.providersList : [];
|
|
40
86
|
return list;
|
|
41
87
|
},
|
|
88
|
+
|
|
89
|
+
displayProviderUrl() {
|
|
90
|
+
return (provider) => getProviderDisplayUrl(provider);
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
isTransformProvider() {
|
|
94
|
+
return (provider) => checkIsTransformProvider(provider);
|
|
95
|
+
},
|
|
42
96
|
installTargetCards() {
|
|
43
97
|
const targets = Array.isArray(this.installStatusTargets) && this.installStatusTargets.length
|
|
44
98
|
? this.installStatusTargets
|
|
@@ -153,7 +153,14 @@ const KNOWN_USAGE_MODEL_PRICING = Object.freeze({
|
|
|
153
153
|
'gpt-5.4': Object.freeze({ input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }),
|
|
154
154
|
'gpt-5.4-mini': Object.freeze({ input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }),
|
|
155
155
|
'gpt-5.3-codex': Object.freeze({ input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }),
|
|
156
|
-
'gpt-5.2-codex': Object.freeze({ input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 })
|
|
156
|
+
'gpt-5.2-codex': Object.freeze({ input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 }),
|
|
157
|
+
'claude-opus-4-6': Object.freeze({ input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75, reasoningOutput: 75 }),
|
|
158
|
+
'claude-opus-4-7': Object.freeze({ input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75, reasoningOutput: 75 }),
|
|
159
|
+
'claude-sonnet-4-6': Object.freeze({ input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75, reasoningOutput: 15 }),
|
|
160
|
+
'claude-haiku-4-5': Object.freeze({ input: 0.8, output: 4, cacheRead: 0.08, cacheWrite: 1, reasoningOutput: 4 }),
|
|
161
|
+
'claude-3-5-sonnet': Object.freeze({ input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75, reasoningOutput: 15 }),
|
|
162
|
+
'claude-3-5-haiku': Object.freeze({ input: 0.8, output: 4, cacheRead: 0.08, cacheWrite: 1, reasoningOutput: 4 }),
|
|
163
|
+
'claude-3-opus': Object.freeze({ input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75, reasoningOutput: 75 })
|
|
157
164
|
});
|
|
158
165
|
|
|
159
166
|
function createUsagePricingEntry(pricing, source) {
|
|
@@ -234,22 +241,17 @@ function resolveUsagePricingForSession(session, pricingIndex, fallbackProvider =
|
|
|
234
241
|
if (knownPricing) {
|
|
235
242
|
return knownPricing;
|
|
236
243
|
}
|
|
244
|
+
const strippedModel = model.replace(/-\d{8}(?=[-_]|$)/, '');
|
|
245
|
+
if (strippedModel !== model) {
|
|
246
|
+
const strippedKnown = pricingIndex.knownByModel instanceof Map ? pricingIndex.knownByModel.get(strippedModel) : null;
|
|
247
|
+
if (strippedKnown) {
|
|
248
|
+
return strippedKnown;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
237
251
|
return null;
|
|
238
252
|
}
|
|
239
253
|
|
|
240
|
-
function shouldEstimateUsageCostForSession(
|
|
241
|
-
if (!session || typeof session !== 'object') {
|
|
242
|
-
return false;
|
|
243
|
-
}
|
|
244
|
-
const source = typeof session.source === 'string' ? session.source.trim().toLowerCase() : '';
|
|
245
|
-
const provider = typeof session.provider === 'string' ? session.provider.trim().toLowerCase() : '';
|
|
246
|
-
const model = typeof session.model === 'string' ? session.model.trim().toLowerCase() : '';
|
|
247
|
-
if (source === 'claude' || provider === 'claude') {
|
|
248
|
-
return false;
|
|
249
|
-
}
|
|
250
|
-
if (/^claude(?:[-_]|$)/.test(model)) {
|
|
251
|
-
return false;
|
|
252
|
-
}
|
|
254
|
+
function shouldEstimateUsageCostForSession() {
|
|
253
255
|
return true;
|
|
254
256
|
}
|
|
255
257
|
|
|
@@ -313,10 +315,11 @@ function estimateUsageCostSummary(sessions, providersList, currentProvider) {
|
|
|
313
315
|
function estimateUsageCostForSession(session, pricingIndex, currentProvider) {
|
|
314
316
|
const inputTokens = Number.isFinite(Number(session.inputTokens)) ? Math.max(0, Math.floor(Number(session.inputTokens))) : null;
|
|
315
317
|
const cachedInputTokens = Number.isFinite(Number(session.cachedInputTokens)) ? Math.max(0, Math.floor(Number(session.cachedInputTokens))) : 0;
|
|
318
|
+
const cacheCreationInputTokens = Number.isFinite(Number(session.cacheCreationInputTokens)) ? Math.max(0, Math.floor(Number(session.cacheCreationInputTokens))) : 0;
|
|
316
319
|
const outputTokens = Number.isFinite(Number(session.outputTokens)) ? Math.max(0, Math.floor(Number(session.outputTokens))) : null;
|
|
317
320
|
const reasoningOutputTokens = Number.isFinite(Number(session.reasoningOutputTokens)) ? Math.max(0, Math.floor(Number(session.reasoningOutputTokens))) : 0;
|
|
318
|
-
const billableInputTokens = Math.max(0, (inputTokens || 0) - cachedInputTokens);
|
|
319
|
-
const fallbackSessionTokens = billableInputTokens + cachedInputTokens + (outputTokens || 0) + reasoningOutputTokens;
|
|
321
|
+
const billableInputTokens = Math.max(0, (inputTokens || 0) - cachedInputTokens - cacheCreationInputTokens);
|
|
322
|
+
const fallbackSessionTokens = billableInputTokens + cachedInputTokens + cacheCreationInputTokens + (outputTokens || 0) + reasoningOutputTokens;
|
|
320
323
|
const totalSessionTokens = Number.isFinite(Number(session.totalTokens))
|
|
321
324
|
? Math.max(0, Math.floor(Number(session.totalTokens)))
|
|
322
325
|
: fallbackSessionTokens;
|
|
@@ -325,12 +328,14 @@ function estimateUsageCostForSession(session, pricingIndex, currentProvider) {
|
|
|
325
328
|
const reasoningRate = pricing
|
|
326
329
|
? ((pricing.reasoningOutput != null ? pricing.reasoningOutput : pricing.output) || 0)
|
|
327
330
|
: 0;
|
|
331
|
+
const visibleOutputTokens = Math.max(0, (outputTokens || 0) - reasoningOutputTokens);
|
|
328
332
|
const estimatedUsd = pricing && hasTokenBreakdown
|
|
329
333
|
? (
|
|
330
334
|
((pricing.input || 0) * billableInputTokens)
|
|
331
335
|
+ ((pricing.cacheRead || 0) * cachedInputTokens)
|
|
336
|
+
+ ((pricing.cacheWrite || 0) * cacheCreationInputTokens)
|
|
332
337
|
+ (reasoningRate * reasoningOutputTokens)
|
|
333
|
-
+ ((pricing.output || 0) *
|
|
338
|
+
+ ((pricing.output || 0) * visibleOutputTokens)
|
|
334
339
|
) / 1000000
|
|
335
340
|
: 0;
|
|
336
341
|
return {
|