dsh-lcx-codex 0.4.2 → 0.4.3-pre.2
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 +116 -202
- package/cordis.patch.yml +3 -20
- package/lib/client.js +273 -146
- package/lib/compact-v2.js +218 -199
- package/lib/dsh-compat.js +227 -100
- package/lib/dsh-responses.js +445 -277
- package/lib/index.js +851 -757
- package/lib/json-store.js +50 -31
- package/lib/native-checkpoint.js +520 -194
- package/lib/responses-request.js +106 -121
- package/lib/responses-stream.js +972 -443
- package/lib/route.js +229 -355
- package/lib/service-mutex.js +73 -64
- package/lib/token-budget.js +176 -108
- package/lib/transport.js +277 -67
- package/lib/types/client/index.d.ts +6 -0
- package/lib/types/compact-v2.d.ts +104 -0
- package/lib/types/dsh-compat.d.ts +78 -0
- package/lib/types/dsh-responses.d.ts +82 -0
- package/lib/types/index.d.ts +83 -0
- package/lib/types/json-store.d.ts +10 -0
- package/lib/types/native-checkpoint.d.ts +213 -0
- package/lib/types/responses-request.d.ts +58 -0
- package/lib/types/responses-stream.d.ts +51 -0
- package/lib/types/route.d.ts +132 -0
- package/lib/types/service-mutex.d.ts +14 -0
- package/lib/types/token-budget.d.ts +50 -0
- package/lib/types/transport.d.ts +20 -0
- package/lib/types/web-run-output.d.ts +29 -0
- package/lib/types/web-search-alpha.d.ts +286 -0
- package/lib/types/web-search-capability.d.ts +26 -0
- package/lib/types/web-search-hosted.d.ts +246 -0
- package/lib/types/web-search-ref-store.d.ts +22 -0
- package/lib/web-run-output.js +167 -18
- package/lib/web-search-alpha.js +865 -163
- package/lib/web-search-capability.js +55 -65
- package/lib/web-search-hosted.js +210 -32
- package/lib/web-search-ref-store.js +63 -59
- package/package.json +79 -27
- package/ARCHITECTURE.md +0 -117
- package/CHANGELOG.md +0 -224
- package/README_EN.md +0 -277
- package/assets/dsh-lcx-codex-banner.jpg +0 -0
- package/lib/legacy-v3.js +0 -20
- package/lib/responses-replay.js +0 -68
- package/scripts/probe-alpha.mjs +0 -43
- package/scripts/validate-dsh-schema.mjs +0 -31
package/lib/client.js
CHANGED
|
@@ -1,168 +1,295 @@
|
|
|
1
|
+
// src/client/index.tsx
|
|
1
2
|
window.__ModuleLoader__.load({
|
|
2
|
-
id:
|
|
3
|
-
factory: (
|
|
4
|
-
const module = { exports: {} }
|
|
5
|
-
const exports = module.exports
|
|
6
|
-
const React =
|
|
7
|
-
const { createSnapshotStore } =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (typeof document !== 'undefined' && !document.querySelector('style[data-plugin-css="dsh-lcx-codex"]')) {
|
|
27
|
-
const tag = document.createElement('style')
|
|
28
|
-
tag.dataset.pluginCss = 'dsh-lcx-codex'
|
|
29
|
-
tag.textContent = css
|
|
30
|
-
document.head.appendChild(tag)
|
|
3
|
+
id: "dsh-lcx-codex",
|
|
4
|
+
factory: (require2) => {
|
|
5
|
+
const module = { exports: {} };
|
|
6
|
+
const exports = module.exports;
|
|
7
|
+
const React = require2("react");
|
|
8
|
+
const { createSnapshotStore } = require2(
|
|
9
|
+
"@deepseek-ai/dsh-client-store"
|
|
10
|
+
);
|
|
11
|
+
const NAMESPACE = "lcx-codex";
|
|
12
|
+
const FIELDS = [
|
|
13
|
+
"enabled",
|
|
14
|
+
"webSearch",
|
|
15
|
+
"advancedHostedSearch",
|
|
16
|
+
"alphaSearch"
|
|
17
|
+
];
|
|
18
|
+
const DEFAULTS = Object.fromEntries(
|
|
19
|
+
FIELDS.map((field) => [field, false])
|
|
20
|
+
);
|
|
21
|
+
const css = `.lcx-card{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;list-style:none}.lcx-head{width:100%;display:flex;justify-content:space-between;padding:14px 16px;border:0;background:transparent;color:inherit}.lcx-body{border-top:1px solid var(--dsw-alias-border-l2);padding:12px 16px}.lcx-row{display:flex;gap:9px;padding:8px 0}.lcx-row small,.lcx-help{display:block;font-size:12px;line-height:17px;color:var(--dsw-alias-label-tertiary)}.lcx-foot{display:flex;justify-content:flex-end;gap:8px;margin-top:10px}.lcx-foot button{padding:6px 12px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:inherit}`;
|
|
22
|
+
if (typeof document !== "undefined" && !document.querySelector('style[data-plugin-css="dsh-lcx-codex"]')) {
|
|
23
|
+
const tag = document.createElement("style");
|
|
24
|
+
tag.dataset.pluginCss = "dsh-lcx-codex";
|
|
25
|
+
tag.textContent = css;
|
|
26
|
+
document.head.appendChild(tag);
|
|
31
27
|
}
|
|
32
28
|
const copy = {
|
|
33
29
|
zh: {
|
|
34
|
-
title:
|
|
35
|
-
desc:
|
|
36
|
-
enabled:
|
|
37
|
-
enabledHelp:
|
|
38
|
-
web:
|
|
39
|
-
webHelp:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
autoThreshold: 'Native 自动压缩阈值(%)',
|
|
49
|
-
autoThresholdHelp: '建议 90%。允许 85–95%;262k 窗口在 90% 时仍约剩 26k tokens。',
|
|
50
|
-
emergencyThreshold: 'DSH 紧急 prune 阈值(%)',
|
|
51
|
-
emergencyThresholdHelp: '建议 95%。达到这里才允许 DSH tool-result-pruner 先救场;必须高于 Native 阈值。',
|
|
52
|
-
fallback: 'Native 失败后回退 DSH basic compaction',
|
|
53
|
-
fallbackHelp: 'Remote-first:只有 Native 请求失败才调用 basic summary,不并行双跑。',
|
|
54
|
-
endpoint: 'Responses 地址',
|
|
55
|
-
model: 'GPT 模型',
|
|
56
|
-
save: '保存', discard: '放弃修改', saving: '保存中…',
|
|
30
|
+
title: "Responses / Codex \u80FD\u529B",
|
|
31
|
+
desc: "LCX \u8DDF\u968F DSH \u5F53\u524D\u4F1A\u8BDD\u9009\u62E9\u7684 GPT Responses route\uFF1B\u6A21\u578B\u3001endpoint \u548C credential \u7EE7\u7EED\u53EA\u7531 DSH \u7BA1\u7406\u3002",
|
|
32
|
+
enabled: "\u542F\u7528 LCX\uFF08\u63A5\u7BA1\u5F53\u524D GPT Responses \u4F1A\u8BDD\uFF09",
|
|
33
|
+
enabledHelp: "\u5207\u6362 Claude\u3001Gemini\u3001DeepSeek \u7B49\u975E GPT \u6A21\u578B\u524D\u5148\u5173\u95ED LCX\uFF1B\u6A21\u578B\u5207\u6362\u672C\u8EAB\u4E0D\u9700\u8981\u91CD\u542F DSH\u3002",
|
|
34
|
+
web: "\u4F7F\u7528 GPT Hosted Search \u4F5C\u4E3A DSH web_search \u540E\u7AEF",
|
|
35
|
+
webHelp: "\u4E0D\u4F1A\u65B0\u589E\u7B2C\u4E8C\u4E2A\u666E\u901A\u641C\u7D22\u5DE5\u5177\uFF1B\u666E\u901A web_search \u81EA\u52A8\u8DDF\u968F\u5F53\u524D Agent \u7684 GPT Responses route\u3002",
|
|
36
|
+
advanced: "\u542F\u7528\u9AD8\u7EA7 Hosted \u5DE5\u5177\uFF08websearch_gpt_advanced\uFF09",
|
|
37
|
+
advancedHelp: "\u53EA\u5728\u9700\u8981\u57DF\u540D\u8FC7\u6EE4\u3001\u4F4D\u7F6E\u3001search context\u3001\u56FE\u7247\u7B49\u539F\u751F Hosted \u53C2\u6570\u65F6\u4F7F\u7528\uFF1B\u9ED8\u8BA4\u5173\u95ED\u4EE5\u4FDD\u6301\u5DE5\u5177 schema \u7A33\u5B9A\u3002",
|
|
38
|
+
alpha: "\u542F\u7528 Alpha command\uFF08websearch_alpha\uFF09",
|
|
39
|
+
alphaHelp: "\u4EC5 capability probe \u5BF9\u5F53\u524D route/schema \u9A8C\u8BC1\u901A\u8FC7\u540E\u624D\u771F\u6B63\u6CE8\u518C\u3002",
|
|
40
|
+
save: "\u4FDD\u5B58",
|
|
41
|
+
discard: "\u653E\u5F03\u4FEE\u6539",
|
|
42
|
+
saving: "\u4FDD\u5B58\u4E2D\u2026",
|
|
43
|
+
saveError: "\u672A\u80FD\u786E\u8BA4\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002\u4FEE\u6539\u5DF2\u4FDD\u7559\uFF0C\u8BF7\u91CD\u8BD5\u6216\u653E\u5F03\u4FEE\u6539\u4EE5\u67E5\u770B\u5F53\u524D\u8BBE\u7F6E\u3002"
|
|
57
44
|
},
|
|
58
45
|
en: {
|
|
59
|
-
title:
|
|
60
|
-
desc:
|
|
61
|
-
enabled:
|
|
62
|
-
enabledHelp:
|
|
63
|
-
web:
|
|
64
|
-
webHelp:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
46
|
+
title: "Responses / Codex capabilities",
|
|
47
|
+
desc: "LCX follows the GPT Responses route selected by the current DSH session. Model, endpoint and credentials remain DSH-owned.",
|
|
48
|
+
enabled: "Enable LCX (own current GPT Responses conversation)",
|
|
49
|
+
enabledHelp: "Turn LCX off before switching to Claude, Gemini, DeepSeek, or another non-GPT model. Model switching itself does not require a DSH restart.",
|
|
50
|
+
web: "Use GPT Hosted Search as DSH web_search backend",
|
|
51
|
+
webHelp: "Keeps DSH web_search as the single ordinary search tool and follows the active Agent GPT Responses route.",
|
|
52
|
+
advanced: "Enable advanced Hosted tool (websearch_gpt_advanced)",
|
|
53
|
+
advancedHelp: "Only for native Hosted controls such as domains, location, context size and image search; off by default for stable tool schemas.",
|
|
54
|
+
alpha: "Enable Alpha command (websearch_alpha)",
|
|
55
|
+
alphaHelp: "Registered only after a matching capability probe.",
|
|
56
|
+
save: "Save",
|
|
57
|
+
discard: "Discard",
|
|
58
|
+
saving: "Saving\u2026",
|
|
59
|
+
saveError: "Could not confirm settings were saved. Changes are kept; retry or discard to view current settings."
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
function valueFrom(snapshot) {
|
|
63
|
+
const value = snapshot.value ?? {};
|
|
64
|
+
return {
|
|
65
|
+
...DEFAULTS,
|
|
66
|
+
...Object.fromEntries(
|
|
67
|
+
FIELDS.map((field) => [field, Boolean(value[field])])
|
|
68
|
+
)
|
|
69
|
+
};
|
|
82
70
|
}
|
|
83
|
-
const lang = () => String(globalThis.navigator?.language ?? '').toLowerCase().startsWith('zh') ? 'zh' : 'en'
|
|
84
|
-
function valueFrom(snapshot) { return { ...DEFAULTS, ...(snapshot.value ?? {}) } }
|
|
85
71
|
class Controller {
|
|
72
|
+
scope;
|
|
73
|
+
draft;
|
|
74
|
+
dirty;
|
|
75
|
+
saving;
|
|
76
|
+
saveError;
|
|
77
|
+
store;
|
|
78
|
+
stop;
|
|
86
79
|
constructor(scope) {
|
|
87
|
-
this.scope = scope;
|
|
88
|
-
this.
|
|
89
|
-
this.
|
|
80
|
+
this.scope = scope;
|
|
81
|
+
this.draft = null;
|
|
82
|
+
this.dirty = false;
|
|
83
|
+
this.saving = false;
|
|
84
|
+
this.saveError = false;
|
|
85
|
+
this.store = createSnapshotStore(this.projection());
|
|
86
|
+
this.stop = scope.subscribe(() => {
|
|
87
|
+
if (!this.dirty) this.draft = null;
|
|
88
|
+
this.publish();
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
snapshot() {
|
|
92
|
+
return this.scope.getSnapshot();
|
|
93
|
+
}
|
|
94
|
+
value() {
|
|
95
|
+
return valueFrom(this.snapshot());
|
|
96
|
+
}
|
|
97
|
+
draftValue() {
|
|
98
|
+
return { ...this.value(), ...this.draft ?? {} };
|
|
90
99
|
}
|
|
91
|
-
snapshot() { return this.scope.getSnapshot() }
|
|
92
|
-
value() { return valueFrom(this.snapshot()) }
|
|
93
|
-
draftValue() { return { ...this.value(), ...(this.draft ?? {}) } }
|
|
94
|
-
field(name) { return this.draftValue()[name] }
|
|
95
100
|
projection() {
|
|
96
|
-
const s = this.snapshot()
|
|
97
|
-
|
|
101
|
+
const s = this.snapshot(), value = this.draftValue(), fields = Object.fromEntries(
|
|
102
|
+
FIELDS.map((field) => [field, { value: Boolean(value[field]) }])
|
|
103
|
+
);
|
|
98
104
|
return {
|
|
99
|
-
available: s.status ===
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
105
|
+
available: s.status === "ready",
|
|
106
|
+
writable: s.writable,
|
|
107
|
+
dirty: this.dirty,
|
|
108
|
+
saving: this.saving,
|
|
109
|
+
saveError: this.saveError,
|
|
110
|
+
...fields
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
publish() {
|
|
114
|
+
this.store.set(this.projection());
|
|
115
|
+
}
|
|
116
|
+
edit(field, value) {
|
|
117
|
+
if (!FIELDS.includes(field) || this.saving || !this.snapshot().writable) return;
|
|
118
|
+
this.draft = {
|
|
119
|
+
...this.draft,
|
|
120
|
+
[field]: Boolean(value)
|
|
121
|
+
};
|
|
122
|
+
if (this.value()[field] === Boolean(value)) delete this.draft[field];
|
|
123
|
+
this.dirty = Object.keys(this.draft).length > 0;
|
|
124
|
+
this.saveError = false;
|
|
125
|
+
this.publish();
|
|
126
|
+
}
|
|
127
|
+
discard() {
|
|
128
|
+
if (this.saving) return;
|
|
129
|
+
this.draft = null;
|
|
130
|
+
this.dirty = false;
|
|
131
|
+
this.saveError = false;
|
|
132
|
+
this.publish();
|
|
106
133
|
}
|
|
107
|
-
publish() { this.store.set(this.projection()) }
|
|
108
|
-
edit(field, value) { this.draft = { ...(this.draft ?? this.value()), [field]: value }; this.dirty = true; this.publish() }
|
|
109
|
-
discard() { this.draft = null; this.dirty = false; this.publish() }
|
|
110
134
|
async save() {
|
|
111
|
-
if (!this.dirty || this.saving || !this.snapshot().writable) return
|
|
112
|
-
const next = this.draftValue(), prev = this.value();
|
|
135
|
+
if (!this.dirty || this.saving || !this.snapshot().writable || this.snapshot().status !== "ready") return;
|
|
136
|
+
const next = this.draftValue(), prev = this.value();
|
|
137
|
+
const fields = FIELDS.filter((field) => next[field] !== prev[field]);
|
|
138
|
+
this.saving = true;
|
|
139
|
+
this.saveError = false;
|
|
140
|
+
this.publish();
|
|
113
141
|
try {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
142
|
+
if (fields.length) {
|
|
143
|
+
await this.scope.mutate(fields.map((field) => ({
|
|
144
|
+
op: "set",
|
|
145
|
+
path: [field],
|
|
146
|
+
value: next[field]
|
|
147
|
+
})));
|
|
148
|
+
if (this.snapshot().status !== "ready" || fields.some((field) => this.value()[field] !== next[field]))
|
|
149
|
+
throw new Error("Settings mutation was not confirmed");
|
|
150
|
+
}
|
|
151
|
+
this.draft = null;
|
|
152
|
+
this.dirty = false;
|
|
153
|
+
} catch {
|
|
154
|
+
this.saveError = true;
|
|
155
|
+
} finally {
|
|
156
|
+
this.saving = false;
|
|
157
|
+
this.publish();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
inject() {
|
|
161
|
+
return {
|
|
162
|
+
hooks: { lcxCard: this.store },
|
|
163
|
+
edit: (field, value) => this.edit(field, value),
|
|
164
|
+
save: () => void this.save(),
|
|
165
|
+
discard: () => this.discard()
|
|
166
|
+
};
|
|
117
167
|
}
|
|
118
|
-
inject() { return { hooks: { lcxCard: this.store }, edit: (f,v) => this.edit(f,v), save: () => void this.save(), discard: () => this.discard() } }
|
|
119
|
-
}
|
|
120
|
-
function Row({ id, label, help, checked, disabled, onChange }) {
|
|
121
|
-
return React.createElement('div', { className:'lcx-row' },
|
|
122
|
-
React.createElement('input', { id, type:'checkbox', checked, disabled, onChange:e=>onChange(e.target.checked) }),
|
|
123
|
-
React.createElement('label', { htmlFor:id }, label, React.createElement('small', null, help)))
|
|
124
168
|
}
|
|
125
|
-
function
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
169
|
+
function Row({
|
|
170
|
+
id,
|
|
171
|
+
label,
|
|
172
|
+
help,
|
|
173
|
+
checked,
|
|
174
|
+
disabled,
|
|
175
|
+
onChange
|
|
176
|
+
}) {
|
|
177
|
+
return React.createElement(
|
|
178
|
+
"div",
|
|
179
|
+
{ className: "lcx-row" },
|
|
180
|
+
React.createElement("input", {
|
|
181
|
+
id,
|
|
182
|
+
type: "checkbox",
|
|
183
|
+
checked,
|
|
184
|
+
disabled,
|
|
185
|
+
onChange: (event) => onChange(event.target.checked)
|
|
186
|
+
}),
|
|
187
|
+
React.createElement(
|
|
188
|
+
"label",
|
|
189
|
+
{ htmlFor: id },
|
|
190
|
+
label,
|
|
191
|
+
React.createElement("small", null, help)
|
|
192
|
+
)
|
|
193
|
+
);
|
|
130
194
|
}
|
|
131
195
|
function Card(props) {
|
|
132
|
-
const t =
|
|
133
|
-
if (!s.available) return null
|
|
134
|
-
const disabled = !s.writable || s.saving
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
React.createElement(
|
|
146
|
-
React.createElement(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
React.createElement(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
196
|
+
const t = props.t, s = props.useLcxCard((state) => state), [open, setOpen] = React.useState(false);
|
|
197
|
+
if (!s.available) return null;
|
|
198
|
+
const disabled = !s.writable || s.saving;
|
|
199
|
+
return React.createElement(
|
|
200
|
+
"li",
|
|
201
|
+
{ className: "lcx-card" },
|
|
202
|
+
React.createElement(
|
|
203
|
+
"button",
|
|
204
|
+
{
|
|
205
|
+
className: "lcx-head",
|
|
206
|
+
type: "button",
|
|
207
|
+
onClick: () => setOpen(!open)
|
|
208
|
+
},
|
|
209
|
+
React.createElement("strong", null, t("title")),
|
|
210
|
+
React.createElement("span", null, open ? "\u2303" : "\u2304")
|
|
211
|
+
),
|
|
212
|
+
open ? React.createElement(
|
|
213
|
+
"div",
|
|
214
|
+
{ className: "lcx-body" },
|
|
215
|
+
React.createElement("p", { className: "lcx-help" }, t("desc")),
|
|
216
|
+
React.createElement(Row, {
|
|
217
|
+
id: "lcx-enabled",
|
|
218
|
+
label: t("enabled"),
|
|
219
|
+
help: t("enabledHelp"),
|
|
220
|
+
checked: s.enabled.value,
|
|
221
|
+
disabled,
|
|
222
|
+
onChange: (value) => props.edit("enabled", value)
|
|
223
|
+
}),
|
|
224
|
+
React.createElement(Row, {
|
|
225
|
+
id: "lcx-web",
|
|
226
|
+
label: t("web"),
|
|
227
|
+
help: t("webHelp"),
|
|
228
|
+
checked: s.webSearch.value,
|
|
229
|
+
disabled: disabled || !s.enabled.value,
|
|
230
|
+
onChange: (value) => props.edit("webSearch", value)
|
|
231
|
+
}),
|
|
232
|
+
React.createElement(Row, {
|
|
233
|
+
id: "lcx-advanced",
|
|
234
|
+
label: t("advanced"),
|
|
235
|
+
help: t("advancedHelp"),
|
|
236
|
+
checked: s.advancedHostedSearch.value,
|
|
237
|
+
disabled: disabled || !s.enabled.value || !s.webSearch.value,
|
|
238
|
+
onChange: (value) => props.edit("advancedHostedSearch", value)
|
|
239
|
+
}),
|
|
240
|
+
React.createElement(Row, {
|
|
241
|
+
id: "lcx-alpha",
|
|
242
|
+
label: t("alpha"),
|
|
243
|
+
help: t("alphaHelp"),
|
|
244
|
+
checked: s.alphaSearch.value,
|
|
245
|
+
disabled: disabled || !s.enabled.value,
|
|
246
|
+
onChange: (value) => props.edit("alphaSearch", value)
|
|
247
|
+
}),
|
|
248
|
+
React.createElement(
|
|
249
|
+
"p",
|
|
250
|
+
{ role: "alert", hidden: !s.saveError },
|
|
251
|
+
s.saveError ? t("saveError") : ""
|
|
252
|
+
),
|
|
253
|
+
React.createElement(
|
|
254
|
+
"div",
|
|
255
|
+
{ className: "lcx-foot" },
|
|
256
|
+
React.createElement(
|
|
257
|
+
"button",
|
|
258
|
+
{ disabled: !s.dirty || disabled, onClick: props.discard },
|
|
259
|
+
t("discard")
|
|
260
|
+
),
|
|
261
|
+
React.createElement(
|
|
262
|
+
"button",
|
|
263
|
+
{ disabled: !s.dirty || disabled, onClick: props.save },
|
|
264
|
+
s.saving ? t("saving") : t("save")
|
|
265
|
+
)
|
|
266
|
+
)
|
|
267
|
+
) : null
|
|
268
|
+
);
|
|
157
269
|
}
|
|
158
|
-
const inject = [
|
|
270
|
+
const inject = ["slots", "locale", "settingsScope"];
|
|
159
271
|
function apply(ctx) {
|
|
160
|
-
const slots = ctx.slots ?? ctx.get(
|
|
161
|
-
if (!slots || !svc) return
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
272
|
+
const slots = ctx.slots ?? ctx.get("slots"), svc = ctx.settingsScope ?? ctx.get("settingsScope"), locale = ctx.locale ?? ctx.get("locale");
|
|
273
|
+
if (!slots || !svc || !locale) return;
|
|
274
|
+
for (const language of ["zh", "en"])
|
|
275
|
+
ctx.effect(() => locale.register(NAMESPACE, language, copy[language]), `lcx-codex ${language} dictionary`);
|
|
276
|
+
const controller = new Controller(svc.bind({ namespace: NAMESPACE }));
|
|
277
|
+
slots.inject(
|
|
278
|
+
"settings.plugin.item",
|
|
279
|
+
() => slots.register(
|
|
280
|
+
{
|
|
281
|
+
name: "settings.plugin.item",
|
|
282
|
+
key: NAMESPACE,
|
|
283
|
+
locale: NAMESPACE,
|
|
284
|
+
inject: () => controller.inject()
|
|
285
|
+
},
|
|
286
|
+
Card
|
|
287
|
+
)
|
|
288
|
+
);
|
|
289
|
+
ctx.effect(() => () => controller.stop(), "lcx-codex settings card");
|
|
165
290
|
}
|
|
166
|
-
exports.apply = apply;
|
|
167
|
-
|
|
168
|
-
|
|
291
|
+
exports.apply = apply;
|
|
292
|
+
exports.inject = inject;
|
|
293
|
+
return module.exports;
|
|
294
|
+
}
|
|
295
|
+
});
|