@anweat/dsh-browser 0.1.15-alpha.1 → 0.1.15
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 +19 -8
- package/cordis.patch.yml +3 -16
- package/lib/automation-assets-rpc.js +25 -44
- package/lib/automation-assets-rpc.js.map +1 -1
- package/lib/client/SettingsCard.d.ts +15 -1
- package/lib/client/SettingsCard.js +50 -13
- package/lib/client/SettingsCard.js.map +1 -1
- package/lib/client/automation-assets-client.js +6 -1
- package/lib/client/automation-assets-client.js.map +1 -1
- package/lib/client/form.d.ts +40 -50
- package/lib/client/form.js +64 -159
- package/lib/client/form.js.map +1 -1
- package/lib/client/index.d.ts +5 -3
- package/lib/client/index.js +9 -6
- package/lib/client/index.js.map +1 -1
- package/lib/client/locales.d.ts +3 -0
- package/lib/client/locales.js +4 -2
- package/lib/client/locales.js.map +1 -1
- package/lib/client.js +187 -484
- package/lib/client.js.map +1 -1
- package/lib/config.js +74 -35
- package/lib/config.js.map +1 -1
- package/lib/deps.js +38 -3
- package/lib/deps.js.map +1 -1
- package/lib/index.d.ts +26 -0
- package/lib/index.js +31 -9
- package/lib/index.js.map +1 -1
- package/lib/settings-scope.d.ts +56 -0
- package/lib/settings-scope.js +51 -0
- package/lib/settings-scope.js.map +1 -0
- package/package.json +40 -35
- package/scripts/check-client-bundle.mjs +6 -2
package/lib/client.js
CHANGED
|
@@ -4,19 +4,16 @@ window.__ModuleLoader__.load({
|
|
|
4
4
|
var module = { exports: {} };
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
7
8
|
let react = require("react");
|
|
8
9
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
10
|
//#region src/client/form.ts
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
value: text.trim()
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
});
|
|
11
|
+
/** A free-text field that clears when emptied, so blanking the control resets it. */
|
|
12
|
+
const textField = (field) => (0, _deepseek_ai_dsh_client_ui_primitives.settingsTextField)(field);
|
|
13
|
+
/**
|
|
14
|
+
* A boolean field. The card renders a checkbox, so the conversion is explicit
|
|
15
|
+
* rather than relying on the shared model's text round-trip.
|
|
16
|
+
*/
|
|
20
17
|
const booleanField = (field) => ({
|
|
21
18
|
field,
|
|
22
19
|
format: (value) => value === true ? "true" : "false",
|
|
@@ -25,6 +22,10 @@ window.__ModuleLoader__.load({
|
|
|
25
22
|
value: text === "true"
|
|
26
23
|
} : void 0
|
|
27
24
|
});
|
|
25
|
+
/**
|
|
26
|
+
* An enumerated field. Accepts only a value on the list, so an unknown string
|
|
27
|
+
* blocks the save instead of writing something the Host would reject.
|
|
28
|
+
*/
|
|
28
29
|
const enumField = (field, values) => ({
|
|
29
30
|
field,
|
|
30
31
|
format: (value) => typeof value === "string" ? value : values[0] ?? "",
|
|
@@ -33,34 +34,22 @@ window.__ModuleLoader__.load({
|
|
|
33
34
|
value: text
|
|
34
35
|
} : void 0
|
|
35
36
|
});
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
value
|
|
45
|
-
} : void 0;
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
const stringArrayField = (field) => ({
|
|
49
|
-
field,
|
|
50
|
-
format: (value) => Array.isArray(value) ? JSON.stringify(value, null, 2) : "",
|
|
51
|
-
parse(text) {
|
|
52
|
-
if (text.trim() === "") return { kind: "clear" };
|
|
53
|
-
try {
|
|
54
|
-
const value = JSON.parse(text);
|
|
55
|
-
return Array.isArray(value) && value.every((entry) => typeof entry === "string") ? {
|
|
37
|
+
/** A whole-number field bounded to a range; an empty draft clears it. */
|
|
38
|
+
const rangedNumberField = (field, min, max) => {
|
|
39
|
+
return {
|
|
40
|
+
field,
|
|
41
|
+
format: (0, _deepseek_ai_dsh_client_ui_primitives.settingsNumberField)(field).format,
|
|
42
|
+
parse(text) {
|
|
43
|
+
if (text.trim() === "") return { kind: "clear" };
|
|
44
|
+
const value = Number(text);
|
|
45
|
+
return Number.isInteger(value) && value >= min && value <= max ? {
|
|
56
46
|
kind: "set",
|
|
57
47
|
value
|
|
58
48
|
} : void 0;
|
|
59
|
-
} catch {
|
|
60
|
-
return;
|
|
61
49
|
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
/** JSON object field: parses to a record, and an empty draft clears the field. */
|
|
64
53
|
const jsonField = (field, validate) => ({
|
|
65
54
|
field,
|
|
66
55
|
format: (value) => value && typeof value === "object" && !Array.isArray(value) ? JSON.stringify(value, null, 2) : "",
|
|
@@ -120,21 +109,22 @@ window.__ModuleLoader__.load({
|
|
|
120
109
|
"auto-draft"
|
|
121
110
|
].includes(String(value.persistenceMode))) return false;
|
|
122
111
|
if (value.activationMode !== void 0 && !["manual", "auto-tested"].includes(String(value.activationMode))) return false;
|
|
112
|
+
const numeric = [
|
|
113
|
+
"minSuccessfulRuns",
|
|
114
|
+
"minDistinctSessions",
|
|
115
|
+
"successWindowDays",
|
|
116
|
+
"minSuccessRate",
|
|
117
|
+
"maxCandidates",
|
|
118
|
+
"candidateTtlDays",
|
|
119
|
+
"maxSuggestionsPerDay",
|
|
120
|
+
"maxDrafts",
|
|
121
|
+
"maxActiveAssets",
|
|
122
|
+
"retrievalTopK",
|
|
123
|
+
"catalogTokenBudget",
|
|
124
|
+
"maxModelDraftWritesPerSession"
|
|
125
|
+
];
|
|
123
126
|
return Object.entries(value).every(([key, entry]) => {
|
|
124
|
-
if (!
|
|
125
|
-
"minSuccessfulRuns",
|
|
126
|
-
"minDistinctSessions",
|
|
127
|
-
"successWindowDays",
|
|
128
|
-
"minSuccessRate",
|
|
129
|
-
"maxCandidates",
|
|
130
|
-
"candidateTtlDays",
|
|
131
|
-
"maxSuggestionsPerDay",
|
|
132
|
-
"maxDrafts",
|
|
133
|
-
"maxActiveAssets",
|
|
134
|
-
"retrievalTopK",
|
|
135
|
-
"catalogTokenBudget",
|
|
136
|
-
"maxModelDraftWritesPerSession"
|
|
137
|
-
].includes(key)) return true;
|
|
127
|
+
if (!numeric.includes(key)) return true;
|
|
138
128
|
return typeof entry === "number" && Number.isFinite(entry) && entry >= 0;
|
|
139
129
|
});
|
|
140
130
|
}
|
|
@@ -145,6 +135,11 @@ window.__ModuleLoader__.load({
|
|
|
145
135
|
return entry === void 0 || typeof entry === "number" && Number.isInteger(entry) && entry >= min && entry <= max;
|
|
146
136
|
});
|
|
147
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* The single-input section fields the card edits, in display order. Every entry
|
|
140
|
+
* must also be `.volatile()` in the Host Config schema: `volatileForm` drops
|
|
141
|
+
* unmarked fields, and the Host would refuse a write to one.
|
|
142
|
+
*/
|
|
148
143
|
const FIELD_SPECS = [
|
|
149
144
|
booleanField("enabled"),
|
|
150
145
|
enumField("automationMode", [
|
|
@@ -155,210 +150,52 @@ window.__ModuleLoader__.load({
|
|
|
155
150
|
]),
|
|
156
151
|
enumField("browserRuntime", ["playwright", "patchright"]),
|
|
157
152
|
textField("channel"),
|
|
158
|
-
|
|
159
|
-
stringArrayField("args"),
|
|
153
|
+
rangedNumberField("cdpPort", 1, 65535),
|
|
160
154
|
booleanField("headless"),
|
|
161
155
|
booleanField("opencliEnabled"),
|
|
162
|
-
jsonField("usagePolicy", validUsagePolicy),
|
|
163
|
-
jsonField("automationAssets", validAssetPolicy),
|
|
164
156
|
booleanField("autoInstall"),
|
|
165
157
|
textField("storageStatePath"),
|
|
166
|
-
jsonField("authProfiles"),
|
|
167
158
|
textField("defaultAuthProfile"),
|
|
168
|
-
jsonField("rulePacks"),
|
|
169
159
|
textField("executablePath"),
|
|
170
160
|
textField("snapshotDir"),
|
|
171
161
|
booleanField("verbose")
|
|
172
162
|
];
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
function same(left, right) {
|
|
180
|
-
return stable(left) === stable(right);
|
|
181
|
-
}
|
|
182
|
-
function createLocalStore(initial) {
|
|
183
|
-
let snapshot = initial;
|
|
184
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
185
|
-
return {
|
|
186
|
-
getSnapshot: () => snapshot,
|
|
187
|
-
subscribe(listener) {
|
|
188
|
-
listeners.add(listener);
|
|
189
|
-
return () => {
|
|
190
|
-
listeners.delete(listener);
|
|
191
|
-
};
|
|
192
|
-
},
|
|
193
|
-
set(next) {
|
|
194
|
-
snapshot = next;
|
|
195
|
-
for (const listener of listeners) listener();
|
|
196
|
-
},
|
|
197
|
-
update(updater) {
|
|
198
|
-
const draft = structuredClone(snapshot);
|
|
199
|
-
updater(draft);
|
|
200
|
-
snapshot = draft;
|
|
201
|
-
for (const listener of listeners) listener();
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
}
|
|
163
|
+
/** The JSON-shaped section fields the card renders as code editors. */
|
|
164
|
+
const JSON_FIELD_SPECS = [jsonField("usagePolicy", validUsagePolicy), jsonField("automationAssets", validAssetPolicy)];
|
|
165
|
+
/** Section fields rendered as JSON code editors rather than single inputs. */
|
|
166
|
+
const JSON_FIELDS = new Set(JSON_FIELD_SPECS.map((spec) => spec.field));
|
|
167
|
+
/** Every field the card renders, in display order. */
|
|
168
|
+
const ALL_FIELD_SPECS = [...FIELD_SPECS, ...JSON_FIELD_SPECS];
|
|
205
169
|
var BrowserSettingsController = class {
|
|
206
|
-
|
|
207
|
-
staged = /* @__PURE__ */ new Map();
|
|
170
|
+
form;
|
|
208
171
|
store;
|
|
209
|
-
unsubscribe;
|
|
210
|
-
saving = false;
|
|
211
|
-
failed = false;
|
|
212
172
|
constructor(scope) {
|
|
213
|
-
this.
|
|
214
|
-
this.store =
|
|
215
|
-
this.unsubscribe = scope.subscribe(() => {
|
|
216
|
-
this.publish();
|
|
217
|
-
});
|
|
173
|
+
this.form = new _deepseek_ai_dsh_client_ui_primitives.SettingsFormModel(scope, [...ALL_FIELD_SPECS]);
|
|
174
|
+
this.store = this.form.bind(() => this.project());
|
|
218
175
|
}
|
|
219
176
|
inject() {
|
|
220
177
|
return {
|
|
221
178
|
hooks: { browserSettings: this.store },
|
|
222
|
-
|
|
223
|
-
this.edit(field, text);
|
|
224
|
-
},
|
|
225
|
-
resetField: (field) => {
|
|
226
|
-
this.resetField(field);
|
|
227
|
-
},
|
|
228
|
-
save: () => {
|
|
229
|
-
this.save();
|
|
230
|
-
},
|
|
231
|
-
discard: () => {
|
|
232
|
-
this.discard();
|
|
233
|
-
}
|
|
179
|
+
...this.form.actions()
|
|
234
180
|
};
|
|
235
181
|
}
|
|
236
182
|
snapshot() {
|
|
237
183
|
return this.store.getSnapshot();
|
|
238
184
|
}
|
|
239
|
-
edit(field, text) {
|
|
240
|
-
this.staged.set(field, {
|
|
241
|
-
text,
|
|
242
|
-
clear: false
|
|
243
|
-
});
|
|
244
|
-
this.failed = false;
|
|
245
|
-
this.publish();
|
|
246
|
-
}
|
|
247
|
-
resetField(field) {
|
|
248
|
-
const spec = this.spec(field);
|
|
249
|
-
this.staged.set(field, {
|
|
250
|
-
text: spec.format(this.baseValue(field)),
|
|
251
|
-
clear: true
|
|
252
|
-
});
|
|
253
|
-
this.failed = false;
|
|
254
|
-
this.publish();
|
|
255
|
-
}
|
|
256
|
-
discard() {
|
|
257
|
-
this.staged.clear();
|
|
258
|
-
this.failed = false;
|
|
259
|
-
this.publish();
|
|
260
|
-
}
|
|
261
|
-
async save() {
|
|
262
|
-
const plan = this.plan();
|
|
263
|
-
if (this.saving || plan.some((item) => item.write === void 0) || plan.length === 0) return;
|
|
264
|
-
this.saving = true;
|
|
265
|
-
this.failed = false;
|
|
266
|
-
this.publish();
|
|
267
|
-
let landed = true;
|
|
268
|
-
try {
|
|
269
|
-
for (const item of plan) {
|
|
270
|
-
if (!item.write) {
|
|
271
|
-
landed = false;
|
|
272
|
-
break;
|
|
273
|
-
}
|
|
274
|
-
if (item.write.kind === "clear") {
|
|
275
|
-
await this.scope.unset(item.field);
|
|
276
|
-
landed = !this.stored(item.field) && landed;
|
|
277
|
-
} else {
|
|
278
|
-
await this.scope.set(item.field, item.write.value);
|
|
279
|
-
landed = same(this.userLayer()?.[item.field], item.write.value) && landed;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
} catch {
|
|
283
|
-
landed = false;
|
|
284
|
-
}
|
|
285
|
-
if (landed) this.staged.clear();
|
|
286
|
-
this.saving = false;
|
|
287
|
-
this.failed = !landed;
|
|
288
|
-
this.publish();
|
|
289
|
-
}
|
|
290
185
|
dispose() {
|
|
291
|
-
this.
|
|
186
|
+
this.form.dispose();
|
|
292
187
|
}
|
|
293
188
|
project() {
|
|
294
189
|
const fields = {};
|
|
295
|
-
for (const spec of FIELD_SPECS) fields[spec.field] = this.field(spec.field);
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
available: this.scope.getSnapshot().status === "ready",
|
|
299
|
-
writable: this.scope.getSnapshot().writable,
|
|
300
|
-
dirty: plan.length > 0,
|
|
301
|
-
invalid: plan.some((item) => item.write === void 0),
|
|
302
|
-
saving: this.saving,
|
|
303
|
-
failed: this.failed,
|
|
304
|
-
fields
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
field(field) {
|
|
308
|
-
const spec = this.spec(field);
|
|
309
|
-
const draft = this.staged.get(field);
|
|
310
|
-
if (!draft) return {
|
|
311
|
-
text: spec.format(this.sectionValue(field)),
|
|
312
|
-
overridden: this.stored(field),
|
|
313
|
-
invalid: false
|
|
314
|
-
};
|
|
315
|
-
const write = draft.clear ? { kind: "clear" } : spec.parse(draft.text);
|
|
190
|
+
for (const spec of FIELD_SPECS) fields[spec.field] = this.form.field(spec.field);
|
|
191
|
+
const jsonFields = {};
|
|
192
|
+
for (const spec of JSON_FIELD_SPECS) jsonFields[spec.field] = this.form.field(spec.field);
|
|
316
193
|
return {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
194
|
+
...this.form.shell(),
|
|
195
|
+
fields,
|
|
196
|
+
jsonFields
|
|
320
197
|
};
|
|
321
198
|
}
|
|
322
|
-
plan() {
|
|
323
|
-
const writes = [];
|
|
324
|
-
for (const [field, draft] of this.staged) {
|
|
325
|
-
const spec = this.spec(field);
|
|
326
|
-
if (draft.clear) {
|
|
327
|
-
if (this.stored(field)) writes.push({
|
|
328
|
-
field,
|
|
329
|
-
write: { kind: "clear" }
|
|
330
|
-
});
|
|
331
|
-
continue;
|
|
332
|
-
}
|
|
333
|
-
if (draft.text === spec.format(this.sectionValue(field))) continue;
|
|
334
|
-
writes.push({
|
|
335
|
-
field,
|
|
336
|
-
write: spec.parse(draft.text)
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
return writes;
|
|
340
|
-
}
|
|
341
|
-
spec(field) {
|
|
342
|
-
const spec = SPEC_BY_FIELD.get(field);
|
|
343
|
-
if (!spec) throw new Error(`unknown browser settings field: ${field}`);
|
|
344
|
-
return spec;
|
|
345
|
-
}
|
|
346
|
-
sectionValue(field) {
|
|
347
|
-
return this.scope.getSnapshot().value?.[field];
|
|
348
|
-
}
|
|
349
|
-
baseValue(field) {
|
|
350
|
-
return this.scope.getSnapshot().base?.[field];
|
|
351
|
-
}
|
|
352
|
-
userLayer() {
|
|
353
|
-
return this.scope.getSnapshot().user;
|
|
354
|
-
}
|
|
355
|
-
stored(field) {
|
|
356
|
-
const user = this.userLayer();
|
|
357
|
-
return user !== void 0 && Object.hasOwn(user, field);
|
|
358
|
-
}
|
|
359
|
-
publish() {
|
|
360
|
-
this.store.set(this.project());
|
|
361
|
-
}
|
|
362
199
|
};
|
|
363
200
|
//#endregion
|
|
364
201
|
//#region src/client/styles.ts
|
|
@@ -430,268 +267,126 @@ window.__ModuleLoader__.load({
|
|
|
430
267
|
}
|
|
431
268
|
//#endregion
|
|
432
269
|
//#region src/client/SettingsCard.tsx
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
270
|
+
/**
|
|
271
|
+
* The browser settings card, as the Plugins page renders it.
|
|
272
|
+
*
|
|
273
|
+
* The page owns the card frame — its title button, disclosure, and artwork come
|
|
274
|
+
* from the slot registration — so this component renders only what goes inside:
|
|
275
|
+
* the one-liner for `view: 'summary'`, and the form body for `view: 'page'`.
|
|
276
|
+
* Drawing our own frame here produced a doubled card and an inner header button
|
|
277
|
+
* that swallowed the platform's clicks.
|
|
278
|
+
*
|
|
279
|
+
* The form chrome is the shared `SettingsForm`/`SettingsValueField` pair from
|
|
280
|
+
* `@deepseek-ai/dsh-client-ui-primitives`, the same components every official
|
|
281
|
+
* settings page uses, so the card matches them without restating their markup.
|
|
282
|
+
* @module dsh-browser/client/SettingsCard
|
|
283
|
+
*/
|
|
284
|
+
/** The copy the shared form frame renders, from this page's dictionary. */
|
|
285
|
+
function formLabels(t) {
|
|
286
|
+
return {
|
|
287
|
+
unavailable: t("unavailable"),
|
|
288
|
+
readOnly: t("readOnly"),
|
|
289
|
+
saveFailed: t("saveFailed"),
|
|
290
|
+
save: t("save"),
|
|
291
|
+
saving: t("saving")
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
const SECTION_LAYOUT = [
|
|
295
|
+
{
|
|
296
|
+
title: "freedom",
|
|
297
|
+
hint: "freedomHint",
|
|
298
|
+
fields: [
|
|
299
|
+
"enabled",
|
|
300
|
+
"automationMode",
|
|
301
|
+
"opencliEnabled"
|
|
457
302
|
]
|
|
458
|
-
}
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
title: "runtime",
|
|
306
|
+
hint: "runtimeHint",
|
|
307
|
+
fields: [
|
|
308
|
+
"browserRuntime",
|
|
309
|
+
"channel",
|
|
310
|
+
"headless",
|
|
311
|
+
"autoInstall",
|
|
312
|
+
"executablePath",
|
|
313
|
+
"cdpPort"
|
|
314
|
+
]
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
title: "advanced",
|
|
318
|
+
hint: "advancedHint",
|
|
319
|
+
fields: [
|
|
320
|
+
"storageStatePath",
|
|
321
|
+
"defaultAuthProfile",
|
|
322
|
+
"snapshotDir",
|
|
323
|
+
"verbose"
|
|
324
|
+
]
|
|
325
|
+
}
|
|
326
|
+
];
|
|
327
|
+
/** The section field a spec names, when it is one of the single-input fields. */
|
|
328
|
+
function sectionField(field) {
|
|
329
|
+
return FIELD_SPECS.some((spec) => spec.field === field) ? field : void 0;
|
|
459
330
|
}
|
|
460
331
|
function SettingsCard(props) {
|
|
461
332
|
const { t } = props;
|
|
462
333
|
const state = props.useBrowserSettings((snapshot) => snapshot);
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
const
|
|
466
|
-
const
|
|
467
|
-
field
|
|
468
|
-
state: state.
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
value: state.fields[field].text,
|
|
478
|
-
disabled,
|
|
479
|
-
"aria-invalid": state.fields[field].invalid || void 0,
|
|
480
|
-
onChange: (event) => props.edit(field, event.currentTarget.value)
|
|
481
|
-
})
|
|
482
|
-
});
|
|
483
|
-
const select = (field, label, hint, options) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldShell, {
|
|
484
|
-
field,
|
|
485
|
-
state: state.fields[field],
|
|
486
|
-
label: t(label),
|
|
487
|
-
hint: state.fields[field].invalid ? t("invalid") : t(hint),
|
|
488
|
-
disabled,
|
|
489
|
-
resetLabel: t("reset"),
|
|
490
|
-
onReset: props.resetField,
|
|
491
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
492
|
-
id: `dsh-browser-${field}`,
|
|
493
|
-
className: styles.input,
|
|
494
|
-
value: state.fields[field].text,
|
|
334
|
+
if (props.view === "summary") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: t("description") });
|
|
335
|
+
const disabled = !state.writable;
|
|
336
|
+
const numeric = /* @__PURE__ */ new Set(["cdpPort"]);
|
|
337
|
+
const field = (spec) => {
|
|
338
|
+
const known = sectionField(spec.field);
|
|
339
|
+
const fieldState = known ? state.fields[known] : state.jsonFields[spec.field];
|
|
340
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SettingsValueField, {
|
|
341
|
+
id: `plugin-config-dsh-browser-${spec.field}`,
|
|
342
|
+
label: t(spec.field),
|
|
343
|
+
hint: t(`${spec.field}Hint`),
|
|
344
|
+
overriddenLabel: t("overridden"),
|
|
345
|
+
resetLabel: t("reset"),
|
|
346
|
+
invalidLabel: t(JSON_FIELDS.has(spec.field) ? "invalidJson" : "invalidNumber"),
|
|
347
|
+
numeric: numeric.has(spec.field),
|
|
495
348
|
disabled,
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
value: state.fields[field].text,
|
|
516
|
-
disabled,
|
|
517
|
-
spellCheck: false,
|
|
518
|
-
"aria-invalid": state.fields[field].invalid || void 0,
|
|
519
|
-
onChange: (event) => props.edit(field, event.currentTarget.value)
|
|
520
|
-
})
|
|
521
|
-
});
|
|
522
|
-
const toggle = (field, label, hint) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
523
|
-
className: styles.toggle,
|
|
524
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
525
|
-
className: styles.toggleLabel,
|
|
526
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
527
|
-
className: styles.check,
|
|
528
|
-
type: "checkbox",
|
|
529
|
-
checked: state.fields[field].text === "true",
|
|
530
|
-
disabled,
|
|
531
|
-
onChange: (event) => props.edit(field, String(event.currentTarget.checked))
|
|
532
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
533
|
-
className: styles.label,
|
|
534
|
-
children: t(label)
|
|
535
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
536
|
-
className: styles.hint,
|
|
537
|
-
children: t(hint)
|
|
538
|
-
})] })]
|
|
539
|
-
}), state.fields[field].overridden ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
540
|
-
type: "button",
|
|
541
|
-
className: styles.reset,
|
|
542
|
-
disabled,
|
|
543
|
-
onClick: () => props.resetField(field),
|
|
544
|
-
children: t("reset")
|
|
545
|
-
}) : null]
|
|
546
|
-
});
|
|
547
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
548
|
-
className: `${styles.card} ${open ? styles.open : ""}`,
|
|
549
|
-
"data-dsh-browser-settings": true,
|
|
550
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
551
|
-
type: "button",
|
|
552
|
-
className: styles.header,
|
|
553
|
-
"aria-expanded": open,
|
|
554
|
-
"aria-label": `${t(open ? "collapse" : "expand")}: ${t("title")}`,
|
|
555
|
-
onClick: () => setOpen(!open),
|
|
556
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
557
|
-
className: styles.head,
|
|
558
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
559
|
-
className: styles.titleRow,
|
|
560
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
561
|
-
className: styles.name,
|
|
562
|
-
children: t("title")
|
|
563
|
-
}), state.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
564
|
-
className: styles.badge,
|
|
565
|
-
children: t("unsaved")
|
|
566
|
-
}) : null]
|
|
567
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
568
|
-
className: styles.description,
|
|
569
|
-
children: t("description")
|
|
349
|
+
...fieldState,
|
|
350
|
+
onEdit: (text) => props.edit(spec.field, text),
|
|
351
|
+
onReset: () => props.resetField(spec.field)
|
|
352
|
+
}, spec.field);
|
|
353
|
+
};
|
|
354
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.SettingsForm, {
|
|
355
|
+
labels: formLabels(t),
|
|
356
|
+
state,
|
|
357
|
+
onSave: props.save,
|
|
358
|
+
onDiscard: props.discard,
|
|
359
|
+
children: [
|
|
360
|
+
SECTION_LAYOUT.map((section) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
361
|
+
className: styles.section,
|
|
362
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
363
|
+
className: styles.sectionHead,
|
|
364
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t(section.title) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t(section.hint) })]
|
|
365
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
366
|
+
className: styles.grid,
|
|
367
|
+
children: section.fields.map((name) => field(FIELD_SPECS.find((spec) => spec.field === name)))
|
|
570
368
|
})]
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
"aria-hidden": "true",
|
|
577
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
578
|
-
d: "M3.5 5.5 7 9l3.5-3.5",
|
|
579
|
-
fill: "none",
|
|
580
|
-
stroke: "currentColor",
|
|
581
|
-
strokeWidth: "1.5"
|
|
582
|
-
})
|
|
583
|
-
})]
|
|
584
|
-
}), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
585
|
-
className: styles.body,
|
|
586
|
-
children: [
|
|
587
|
-
!state.writable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
588
|
-
className: styles.notice,
|
|
589
|
-
role: "status",
|
|
590
|
-
children: t("readOnly")
|
|
591
|
-
}) : null,
|
|
592
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
593
|
-
className: styles.section,
|
|
594
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
369
|
+
}, section.title)),
|
|
370
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
371
|
+
className: styles.section,
|
|
372
|
+
children: [
|
|
373
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
595
374
|
className: styles.sectionHead,
|
|
596
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("
|
|
597
|
-
}),
|
|
375
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("usage") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("usageHint") })]
|
|
376
|
+
}),
|
|
377
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
598
378
|
className: styles.grid,
|
|
599
|
-
children:
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
}),
|
|
611
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
612
|
-
className: styles.section,
|
|
613
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
614
|
-
className: styles.sectionHead,
|
|
615
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("runtime") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("runtimeHint") })]
|
|
616
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
617
|
-
className: styles.grid,
|
|
618
|
-
children: [
|
|
619
|
-
select("browserRuntime", "browserRuntime", "browserRuntimeHint", ["playwright", "patchright"]),
|
|
620
|
-
text("channel", "channel", "channelHint"),
|
|
621
|
-
toggle("headless", "headless", "headlessHint"),
|
|
622
|
-
toggle("autoInstall", "autoInstall", "autoInstallHint"),
|
|
623
|
-
text("executablePath", "executablePath", "executablePathHint"),
|
|
624
|
-
text("cdpPort", "cdpPort", "cdpPortHint"),
|
|
625
|
-
json("args", "args", "argsHint", 5)
|
|
626
|
-
]
|
|
627
|
-
})]
|
|
628
|
-
}),
|
|
629
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
630
|
-
className: styles.section,
|
|
631
|
-
children: [
|
|
632
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
633
|
-
className: styles.sectionHead,
|
|
634
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("usage") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("usageHint") })]
|
|
635
|
-
}),
|
|
636
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
637
|
-
className: styles.grid,
|
|
638
|
-
children: [json("usagePolicy", "usagePolicy", "usagePolicyHint", 10), json("automationAssets", "automationAssets", "automationAssetsHint", 14)]
|
|
639
|
-
}),
|
|
640
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
641
|
-
className: styles.notice,
|
|
642
|
-
role: "note",
|
|
643
|
-
children: t("restart")
|
|
644
|
-
})
|
|
645
|
-
]
|
|
646
|
-
}),
|
|
647
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutomationAssetsPanel, { ...props }),
|
|
648
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
649
|
-
className: styles.advanced,
|
|
650
|
-
children: [
|
|
651
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t("advanced") }),
|
|
652
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
653
|
-
className: styles.hint,
|
|
654
|
-
children: t("advancedHint")
|
|
655
|
-
}),
|
|
656
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
657
|
-
className: styles.grid,
|
|
658
|
-
children: [
|
|
659
|
-
text("storageStatePath", "storageStatePath", "storageStatePathHint"),
|
|
660
|
-
text("defaultAuthProfile", "defaultAuthProfile", "defaultAuthProfileHint"),
|
|
661
|
-
json("authProfiles", "authProfiles", "authProfilesHint"),
|
|
662
|
-
json("rulePacks", "rulePacks", "rulePacksHint"),
|
|
663
|
-
text("snapshotDir", "snapshotDir", "snapshotDirHint"),
|
|
664
|
-
toggle("verbose", "verbose", "verboseHint")
|
|
665
|
-
]
|
|
666
|
-
})
|
|
667
|
-
]
|
|
668
|
-
}),
|
|
669
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
670
|
-
className: styles.footer,
|
|
671
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
672
|
-
className: state.failed ? styles.failed : styles.status,
|
|
673
|
-
role: "status",
|
|
674
|
-
"aria-live": "polite",
|
|
675
|
-
children: t(state.failed ? "saveFailed" : state.invalid ? "invalidSave" : state.dirty ? "pending" : "saved")
|
|
676
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
677
|
-
className: styles.actions,
|
|
678
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
679
|
-
type: "button",
|
|
680
|
-
className: styles.secondary,
|
|
681
|
-
disabled: !state.dirty || state.saving,
|
|
682
|
-
onClick: props.discard,
|
|
683
|
-
children: t("discard")
|
|
684
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
685
|
-
type: "button",
|
|
686
|
-
className: styles.primary,
|
|
687
|
-
disabled: !state.dirty || state.invalid || state.saving || !state.writable,
|
|
688
|
-
onClick: props.save,
|
|
689
|
-
children: t(state.saving ? "saving" : "save")
|
|
690
|
-
})]
|
|
691
|
-
})]
|
|
692
|
-
})
|
|
693
|
-
]
|
|
694
|
-
}) : null]
|
|
379
|
+
children: JSON_FIELD_SPECS.map((spec) => field(spec))
|
|
380
|
+
}),
|
|
381
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
382
|
+
className: styles.notice,
|
|
383
|
+
role: "note",
|
|
384
|
+
children: t("restart")
|
|
385
|
+
})
|
|
386
|
+
]
|
|
387
|
+
}),
|
|
388
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutomationAssetsPanel, { ...props })
|
|
389
|
+
]
|
|
695
390
|
});
|
|
696
391
|
}
|
|
697
392
|
function AutomationAssetsPanel(props) {
|
|
@@ -1022,6 +717,9 @@ window.__ModuleLoader__.load({
|
|
|
1022
717
|
verbose: "详细日志",
|
|
1023
718
|
verboseHint: "输出启动和诊断信息。",
|
|
1024
719
|
reset: "恢复部署值",
|
|
720
|
+
overridden: "已覆盖",
|
|
721
|
+
invalidNumber: "请填写数字,留空表示使用默认值。",
|
|
722
|
+
unavailable: "该插件当前未加载,暂时无法配置。",
|
|
1025
723
|
invalid: "值无效,请检查格式或范围。",
|
|
1026
724
|
invalidJson: "JSON 或数值范围无效。",
|
|
1027
725
|
restart: "保存后完整重启 profile,运行时和工具目录才会重新注册。",
|
|
@@ -1111,6 +809,9 @@ window.__ModuleLoader__.load({
|
|
|
1111
809
|
verbose: "Verbose logs",
|
|
1112
810
|
verboseHint: "Emit startup and diagnostic details.",
|
|
1113
811
|
reset: "Restore deployed",
|
|
812
|
+
overridden: "Overridden",
|
|
813
|
+
invalidNumber: "Enter a number, or leave blank to use the default.",
|
|
814
|
+
unavailable: "This plugin is not loaded, so it cannot be configured right now.",
|
|
1114
815
|
invalid: "Invalid value. Check format and bounds.",
|
|
1115
816
|
invalidJson: "Invalid JSON or numeric bounds.",
|
|
1116
817
|
restart: "Fully restart the profile after saving so runtime and tool catalogs are re-registered.",
|
|
@@ -1151,6 +852,8 @@ window.__ModuleLoader__.load({
|
|
|
1151
852
|
}
|
|
1152
853
|
};
|
|
1153
854
|
}
|
|
855
|
+
/** This plugin's private RPC channel, matching the Host half. */
|
|
856
|
+
const CHANNEL = "/dsh-browser-assets";
|
|
1154
857
|
var AutomationAssetsController = class {
|
|
1155
858
|
rpc;
|
|
1156
859
|
store = localStore({
|
|
@@ -1254,7 +957,7 @@ window.__ModuleLoader__.load({
|
|
|
1254
957
|
}
|
|
1255
958
|
}
|
|
1256
959
|
async call(endpoint, payload) {
|
|
1257
|
-
const result = await this.rpc.call(
|
|
960
|
+
const result = await this.rpc.call(CHANNEL, endpoint, payload);
|
|
1258
961
|
if (!result.ok) throw new Error(result.error.message);
|
|
1259
962
|
return result.value;
|
|
1260
963
|
}
|
|
@@ -1278,7 +981,7 @@ window.__ModuleLoader__.load({
|
|
|
1278
981
|
"slots",
|
|
1279
982
|
"locale",
|
|
1280
983
|
"connection",
|
|
1281
|
-
"
|
|
984
|
+
"configForms"
|
|
1282
985
|
];
|
|
1283
986
|
const NS = "dsh-browser.card";
|
|
1284
987
|
function apply(ctx) {
|
|
@@ -1287,13 +990,13 @@ window.__ModuleLoader__.load({
|
|
|
1287
990
|
zh,
|
|
1288
991
|
en
|
|
1289
992
|
}), "dsh-browser: settings dictionaries");
|
|
1290
|
-
const controller = new BrowserSettingsController(ctx.
|
|
993
|
+
const controller = new BrowserSettingsController(ctx.configForms.get(SETTINGS_NAMESPACE));
|
|
1291
994
|
const assets = new AutomationAssetsController(ctx.connection.rpc);
|
|
1292
995
|
ctx.effect(() => () => controller.dispose(), "dsh-browser: settings controller");
|
|
1293
996
|
ctx.effect(() => () => assets.dispose(), "dsh-browser: automation assets controller");
|
|
1294
|
-
ctx.slots.inject("
|
|
1295
|
-
name: "
|
|
1296
|
-
key:
|
|
997
|
+
ctx.effect(() => ctx.configForms.whileServed([SETTINGS_NAMESPACE], () => ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({
|
|
998
|
+
name: "plugins.bundle.config",
|
|
999
|
+
key: "@anweat/dsh-browser",
|
|
1297
1000
|
locale: NS,
|
|
1298
1001
|
inject: () => {
|
|
1299
1002
|
const settingsProps = controller.inject();
|
|
@@ -1307,7 +1010,7 @@ window.__ModuleLoader__.load({
|
|
|
1307
1010
|
}
|
|
1308
1011
|
};
|
|
1309
1012
|
}
|
|
1310
|
-
}, SettingsCard));
|
|
1013
|
+
}, SettingsCard))), "dsh-browser: settings page");
|
|
1311
1014
|
}
|
|
1312
1015
|
//#endregion
|
|
1313
1016
|
exports.NS = NS;
|