@wenaixi/dsh-superpower 7.6.0 → 7.7.1

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/lib/client.js CHANGED
@@ -31,6 +31,7 @@ window.__ModuleLoader__.load({
31
31
  var PACKAGE_NAME = '@wenaixi/dsh-superpower';
32
32
  var NS = 'dsh-superpower';
33
33
  var DISABLED_FIELD = 'disabled';
34
+ var LANGUAGE_FIELD = 'language';
34
35
  /* v7.3.0 及之前的双侧禁言表。面板写入成功后会把它们 unset,
35
36
  这里仍需列出:迁移那批操作的路径必须与 schema 里的字段名逐字一致。 */
36
37
  var LEGACY_FIELDS = ['modelDisabled', 'userDisabled'];
@@ -140,6 +141,12 @@ window.__ModuleLoader__.load({
140
141
  '@media (prefers-reduced-motion:reduce){.spSw *{transition:none!important}}',
141
142
  ].join('\n');
142
143
 
144
+ /**
145
+ * 已知标准技能名白名单映射。
146
+ */
147
+ var KNOWN_SKILL_MAP = {};
148
+ SKILL_CATALOG.forEach(function (skill) { KNOWN_SKILL_MAP[skill.name] = true; });
149
+
143
150
  /**
144
151
  * 读取禁言字典里某个技能是否被关闭。缺项与 falsy 一律视为开启。
145
152
  */
@@ -148,105 +155,384 @@ window.__ModuleLoader__.load({
148
155
  }
149
156
 
150
157
  /**
151
- * 组装一次写入的全部操作:主写入 + 两条清理旧表的 unset。
152
- *
153
- * 清理动作与主写合在同一次 mutate 里,因为 ConfigForm 的 mutate 是一批
154
- * 操作共享一个 revision 栅栏、一次校验、一次持久化决策。这样不存在
155
- * 「新表写了一部分、旧表还留着」的中间态,也省掉每技能一次额外往返。
156
- * op 为 enable 时 unset 路径即恢复继承的默认值。
158
+ * 容灾清洗并提取禁言字典。
159
+ * 1. 过滤非合法技能名与原型污染键;
160
+ * 2. 宽容识别非标真值(true, "true", 1, "1", "yes", "on", "disabled");
161
+ * 3. 忽略假值(false, "false", 0, "no", "off" 等)。
157
162
  */
158
- /* 语言偏好字段:'zh' | 'en' 显式固定;缺失时跟随宿主界面语言(locale active)。 */
159
- var LANGUAGE_FIELD = 'language';
163
+ function extractCleanDisabled(value) {
164
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
165
+ return Object.create(null);
166
+ }
167
+ var clean = Object.create(null);
168
+ Object.keys(value).forEach(function (key) {
169
+ if (key === '__proto__' || key === 'constructor' || key === 'prototype') return;
170
+ if (!KNOWN_SKILL_MAP[key]) return;
171
+ var val = value[key];
172
+ if (
173
+ val === true ||
174
+ val === 'true' ||
175
+ val === 1 ||
176
+ val === '1' ||
177
+ val === 'yes' ||
178
+ val === 'on' ||
179
+ val === 'disabled'
180
+ ) {
181
+ clean[key] = true;
182
+ }
183
+ });
184
+ return clean;
185
+ }
160
186
 
161
187
  /**
162
- * 读取当前语言偏好(三态):'zh'/'en' 显式值原样;缺项为 undefined(跟随宿主)。
163
- * 与宿主侧 readSwitches 同规则,缺失绝不折叠成 zh —— 否则面板无法表达「跟随宿主」。
188
+ * 读取当前语言偏好(三态,含容灾自愈提取):
189
+ * 支持从非标语言码(如 'zh-CN', 'zh_CN', 'en-US', 'chinese' 等)自愈归一化;
190
+ * 缺项或未知输入返回 undefined(跟随宿主)。
164
191
  */
165
192
  function readLanguage(value) {
166
193
  var raw = value && value[LANGUAGE_FIELD];
167
- return raw === 'zh' || raw === 'en' ? raw : undefined;
194
+ if (typeof raw !== 'string') return undefined;
195
+ var lower = raw.trim().toLowerCase().replace(/_/g, '-');
196
+ if (lower === 'zh' || lower.indexOf('zh-') === 0 || lower === 'chinese') return 'zh';
197
+ if (lower === 'en' || lower.indexOf('en-') === 0 || lower === 'english') return 'en';
198
+ return undefined;
199
+ }
200
+
201
+ /**
202
+ * 纯函数探测配置是否包含损坏数据、非标格式或需要自愈修复的结构。
203
+ */
204
+ function isConfigCorrupted(value) {
205
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return true;
206
+ var rawDisabled = value[DISABLED_FIELD];
207
+ if (rawDisabled !== undefined && rawDisabled !== null) {
208
+ if (typeof rawDisabled !== 'object' || Array.isArray(rawDisabled)) return true;
209
+ var keys = Object.keys(rawDisabled);
210
+ for (var i = 0; i < keys.length; i++) {
211
+ var k = keys[i];
212
+ if (!KNOWN_SKILL_MAP[k]) return true;
213
+ if (rawDisabled[k] !== true) return true; // 非标准布尔值或残留假值
214
+ }
215
+ }
216
+ var rawLang = value[LANGUAGE_FIELD];
217
+ if (rawLang !== undefined && rawLang !== null && rawLang !== 'zh' && rawLang !== 'en') {
218
+ return true;
219
+ }
220
+ return false;
168
221
  }
169
222
 
170
- function switchOps(names, op, legacyCarry) {
171
- var list = Array.isArray(names) ? names : [names];
172
- var ops = [];
173
- if (legacyCarry) {
174
- Object.keys(legacyCarry).forEach(function (key) {
175
- if (legacyCarry[key] === true && list.indexOf(key) < 0) {
176
- ops.push({ op: 'set', path: [DISABLED_FIELD, key], value: true });
223
+ /**
224
+ * 客户端配置控制器深度模块 (Deep Module):
225
+ * 将 DSH ConfigForm 订阅、批处理 ops 拍平、旧表原子继承、disposed 拦截与堆栈归集彻底封闭在门后。
226
+ */
227
+ class SwitchPanelModel {
228
+ constructor(scope, options) {
229
+ this.scope = scope;
230
+ this.t = (options && options.t) || ((k) => k);
231
+ this.allNames = (options && options.allNames) || [];
232
+ this.skills = (options && options.skills) || SKILL_CATALOG;
233
+ this.keyword = '';
234
+ this.listeners = new Set();
235
+ this.pending = {};
236
+ this.failures = {};
237
+ this.unsubscribe = null;
238
+ this._bindScope(scope);
239
+ }
240
+
241
+ _bindScope(scope) {
242
+ if (this.scope !== scope) {
243
+ if (this.unsubscribe) {
244
+ this.unsubscribe();
245
+ this.unsubscribe = null;
177
246
  }
247
+ this.scope = scope;
248
+ }
249
+ if (this.scope && typeof this.scope.subscribe === 'function' && !this.unsubscribe) {
250
+ this.unsubscribe = this.scope.subscribe(() => this._notify());
251
+ }
252
+ }
253
+
254
+ updateScope(nextScope) {
255
+ this._bindScope(nextScope);
256
+ this._notify();
257
+ }
258
+
259
+ subscribe(listener) {
260
+ this.listeners.add(listener);
261
+ return () => this.listeners.delete(listener);
262
+ }
263
+
264
+ _notify() {
265
+ this.listeners.forEach((fn) => {
266
+ try { fn(); } catch (e) {}
178
267
  });
179
268
  }
180
- list.forEach(function (name) {
181
- if (op === 'disable') {
182
- ops.push({ op: 'set', path: [DISABLED_FIELD, name], value: true });
269
+
270
+ getSnapshot() {
271
+ var snap = (this.scope && typeof this.scope.getSnapshot === 'function')
272
+ ? this.scope.getSnapshot()
273
+ : { status: 'loading', writable: false, value: {} };
274
+ var value = snap.value || {};
275
+ var rawDisabled = value[DISABLED_FIELD];
276
+ var cleanDisabled = extractCleanDisabled(rawDisabled);
277
+ var rawDisabledExists = rawDisabled && typeof rawDisabled === 'object' && !Array.isArray(rawDisabled);
278
+ var legacyActive = !rawDisabledExists || Object.keys(cleanDisabled).length === 0;
279
+
280
+ var disabled;
281
+ if (!legacyActive && rawDisabledExists) {
282
+ disabled = cleanDisabled;
183
283
  } else {
184
- ops.push({ op: 'unset', path: [DISABLED_FIELD, name] });
284
+ var legModel = extractCleanDisabled(value.modelDisabled);
285
+ var legUser = extractCleanDisabled(value.userDisabled);
286
+ disabled = Object.assign({}, legModel, legUser);
185
287
  }
186
- });
187
- return ops.concat(LEGACY_FIELDS.map(function (field) {
188
- return { op: 'unset', path: [field] };
189
- }));
190
- }
191
288
 
192
- /**
193
- * 提交一批写入并按技能名归集失败原因。settle 后清掉这些技能的忙碌态。
194
- *
195
- * 用户只要在面板动过一次开关,profile 里就只剩 disabled 一个字段。
196
- */
197
- function submit(form, t, names, op, setPending, setFailures, opsOverride, legacyCarry) {
198
- var clear = function (prev) {
199
- var next = {};
200
- Object.keys(prev).forEach(function (key) {
201
- if (names.indexOf(key) < 0) next[key] = prev[key];
289
+ var language = readLanguage(value);
290
+ var corrupted = isConfigCorrupted(value);
291
+
292
+ return {
293
+ status: snap.status || 'ready',
294
+ writable: snap.writable !== false && snap.mode !== 'memory',
295
+ disabled: disabled,
296
+ legacyActive: legacyActive,
297
+ language: language,
298
+ langConfigured: language !== undefined,
299
+ langValue: language !== undefined ? language : 'auto',
300
+ keyword: this.keyword,
301
+ corrupted: corrupted,
302
+ pending: this.pending,
303
+ failures: this.failures,
304
+ };
305
+ }
306
+
307
+ buildRepairOps() {
308
+ var snap = this.getSnapshot();
309
+ var ops = [];
310
+ var disabled = snap.disabled;
311
+ Object.keys(disabled).forEach(function (name) {
312
+ if (disabled[name] === true && KNOWN_SKILL_MAP[name]) {
313
+ ops.push({ op: 'set', path: [DISABLED_FIELD, name], value: true });
314
+ }
202
315
  });
203
- return next;
204
- };
205
- setPending(function (prev) {
206
- var next = clear(prev);
207
- names.forEach(function (name) { next[name] = true; });
208
- return next;
209
- });
210
- var ops = opsOverride || switchOps(names, op, legacyCarry);
211
- var work = form.mutate(ops).then(function (accepted) {
212
- if (accepted === false) throw new Error(t('writeFailed'));
213
- });
214
- work.then(function () {
215
- setFailures(clear);
216
- }, function (error) {
217
- console.error('[dsh-superpower] form.mutate failed:', error);
218
- setFailures(function (prev) {
219
- var next = clear(prev);
220
- var message = t('writeFailed') + ': ' + String(error && error.message ? error.message : error);
221
- names.forEach(function (name) { next[name] = message; });
222
- return next;
316
+ var rawValue = (this.scope && typeof this.scope.getSnapshot === 'function' ? this.scope.getSnapshot().value : {}) || {};
317
+ var rawDisabled = rawValue[DISABLED_FIELD];
318
+ if (rawDisabled && typeof rawDisabled === 'object' && !Array.isArray(rawDisabled)) {
319
+ Object.keys(rawDisabled).forEach(function (k) {
320
+ if (!disabled[k] || !KNOWN_SKILL_MAP[k]) {
321
+ ops.push({ op: 'unset', path: [DISABLED_FIELD, k] });
322
+ }
323
+ });
324
+ }
325
+ if (snap.language !== undefined) {
326
+ ops.push({ op: 'set', path: [LANGUAGE_FIELD], value: snap.language });
327
+ } else if (rawValue[LANGUAGE_FIELD] !== undefined) {
328
+ ops.push({ op: 'unset', path: [LANGUAGE_FIELD] });
329
+ }
330
+ LEGACY_FIELDS.forEach(function (field) {
331
+ ops.push({ op: 'unset', path: [field] });
223
332
  });
224
- }).then(function () {
225
- setPending(clear);
226
- });
333
+ return ops;
334
+ }
335
+
336
+ async repairConfig(force) {
337
+ var snap = this.getSnapshot();
338
+ if ((!force && !snap.corrupted) || !snap.writable || !this.scope || this.scope.disposed) {
339
+ return false;
340
+ }
341
+ if (this._repairing) return false;
342
+ this._repairing = true;
343
+ try {
344
+ var ops = this.buildRepairOps();
345
+ if (ops.length > 0) {
346
+ return await this.scope.mutate(ops);
347
+ }
348
+ } catch (e) {
349
+ console.error('[dsh-superpower] repairConfig failed:', e);
350
+ } finally {
351
+ this._repairing = false;
352
+ }
353
+ return false;
354
+ }
355
+
356
+ setKeyword(query) {
357
+ var next = String(query || '');
358
+ if (this.keyword !== next) {
359
+ this.keyword = next;
360
+ this._notify();
361
+ }
362
+ }
363
+
364
+ getVisibleSkills(hostActive) {
365
+ var snap = this.getSnapshot();
366
+ var language = snap.language;
367
+ var effective = language === undefined ? (hostActive === 'en' ? 'en' : 'zh') : language;
368
+ var lower = this.keyword.trim().toLowerCase();
369
+ var list = this.skills;
370
+ var skillText = function (skill) {
371
+ return effective === 'en' && skill.descriptionEn ? skill.descriptionEn : skill.description;
372
+ };
373
+ var matches = lower === ''
374
+ ? list
375
+ : list.filter(function (skill) {
376
+ var name = skill.name.toLowerCase();
377
+ return name.indexOf(lower) >= 0
378
+ || skill.description.toLowerCase().indexOf(lower) >= 0
379
+ || (skill.descriptionEn || '').toLowerCase().indexOf(lower) >= 0;
380
+ });
381
+ return matches.map(function (skill) {
382
+ return Object.assign({}, skill, { displayText: skillText(skill) });
383
+ });
384
+ }
385
+
386
+ _buildOps(names, op, legacyCarry) {
387
+ var list = Array.isArray(names) ? names : [names];
388
+ var ops = [];
389
+ if (legacyCarry) {
390
+ Object.keys(legacyCarry).forEach(function (key) {
391
+ if (legacyCarry[key] === true && list.indexOf(key) < 0) {
392
+ ops.push({ op: 'set', path: [DISABLED_FIELD, key], value: true });
393
+ }
394
+ });
395
+ }
396
+ list.forEach(function (name) {
397
+ if (op === 'disable') {
398
+ ops.push({ op: 'set', path: [DISABLED_FIELD, name], value: true });
399
+ } else {
400
+ ops.push({ op: 'unset', path: [DISABLED_FIELD, name] });
401
+ }
402
+ });
403
+ return ops.concat(LEGACY_FIELDS.map(function (field) {
404
+ return { op: 'unset', path: [field] };
405
+ }));
406
+ }
407
+
408
+ async _submit(names, ops) {
409
+ if (!this.scope || this.scope.disposed || typeof this.scope.mutate !== 'function') {
410
+ var err = new Error(this.t('hostUnavailable'));
411
+ console.error('[dsh-superpower] form.mutate failed:', err);
412
+ this._setFailures(names, this.t('writeFailed') + ': ' + err.message);
413
+ return false;
414
+ }
415
+
416
+ this._setPending(names, true);
417
+ this._clearFailures(names);
418
+
419
+ try {
420
+ var accepted = await this.scope.mutate(ops);
421
+ if (accepted === false) {
422
+ throw new Error(this.t('writeFailed'));
423
+ }
424
+ this._clearFailures(names);
425
+ return true;
426
+ } catch (error) {
427
+ console.error('[dsh-superpower] form.mutate failed:', error);
428
+ var msg = this.t('writeFailed') + ': ' + String(error && error.message ? error.message : error);
429
+ this._setFailures(names, msg);
430
+ return false;
431
+ } finally {
432
+ this._setPending(names, false);
433
+ }
434
+ }
435
+
436
+ _setPending(names, isPending) {
437
+ var next = Object.assign({}, this.pending);
438
+ names.forEach(function (name) {
439
+ if (isPending) next[name] = true;
440
+ else delete next[name];
441
+ });
442
+ this.pending = next;
443
+ this._notify();
444
+ }
445
+
446
+ _setFailures(names, message) {
447
+ var next = Object.assign({}, this.failures);
448
+ names.forEach(function (name) { next[name] = message; });
449
+ this.failures = next;
450
+ this._notify();
451
+ }
452
+
453
+ _clearFailures(names) {
454
+ var next = Object.assign({}, this.failures);
455
+ var changed = false;
456
+ names.forEach(function (name) {
457
+ if (next[name]) {
458
+ delete next[name];
459
+ changed = true;
460
+ }
461
+ });
462
+ if (changed) {
463
+ this.failures = next;
464
+ this._notify();
465
+ }
466
+ }
467
+
468
+ toggle(name, nextState) {
469
+ var snap = this.getSnapshot();
470
+ var op = nextState ? 'enable' : 'disable';
471
+ var legacyCarry = snap.legacyActive ? snap.disabled : null;
472
+ var ops = this._buildOps([name], op, legacyCarry);
473
+ return this._submit([name], ops);
474
+ }
475
+
476
+ setLanguage(next) {
477
+ var ops = next === 'auto'
478
+ ? [{ op: 'unset', path: [LANGUAGE_FIELD] }]
479
+ : [{ op: 'set', path: [LANGUAGE_FIELD], value: next }];
480
+ return this._submit(['language'], ops);
481
+ }
482
+
483
+ enableAll() {
484
+ var ops = this._buildOps(this.allNames, 'enable');
485
+ return this._submit(this.allNames, ops);
486
+ }
487
+
488
+ disableAll() {
489
+ var ops = this._buildOps(this.allNames, 'disable');
490
+ return this._submit(this.allNames, ops);
491
+ }
492
+
493
+ resetAll() {
494
+ // Q2 裁决:恢复默认纯粹重置技能禁言表,保持语言偏好正交独立
495
+ return this.enableAll();
496
+ }
497
+
498
+ dispose() {
499
+ if (this.unsubscribe) {
500
+ this.unsubscribe();
501
+ this.unsubscribe = null;
502
+ }
503
+ this.listeners.clear();
504
+ }
227
505
  }
228
506
 
229
507
  /**
230
- * 技能开关面板。每个技能一个开关,同时决定模型可见性与用户可调用性。
508
+ * 技能开关面板 (View)。纯渲染视图,完全由 SwitchPanelModel 控制器驱动。
231
509
  *
232
- * props.useSwitches 来自 inject 面绑定好的 ConfigForm 选择器 hook;
233
- * props.actions 是本面板独占的写操作面。
510
+ * props.actions.form 是本面板绑定的 ConfigForm 控制器。
234
511
  */
235
512
  function SkillSwitchPanel(props) {
236
513
  var t = props.t;
237
514
  var form = props.actions.form;
238
- var state = props.useSwitches(function (value) { return value; });
239
515
  var hostActive = props.useLocaleActive(function (v) { return v && v.preference === 'en' ? 'en' : 'zh'; });
516
+ var allNames = SKILL_CATALOG.map(function (skill) { return skill.name; });
517
+
518
+ var modelRef = React.useRef(null);
519
+ if (!modelRef.current) {
520
+ modelRef.current = new SwitchPanelModel(form, { t: t, allNames: allNames });
521
+ } else {
522
+ modelRef.current.updateScope(form);
523
+ }
240
524
 
241
- var keywordState = React.useState('');
242
- var keyword = keywordState[0];
243
- var setKeyword = keywordState[1];
244
- var pendingState = React.useState({});
245
- var pending = pendingState[0];
246
- var setPending = pendingState[1];
247
- var failuresState = React.useState({});
248
- var failures = failuresState[0];
249
- var setFailures = failuresState[1];
525
+ React.useEffect(() => {
526
+ return () => {
527
+ if (modelRef.current) modelRef.current.dispose();
528
+ };
529
+ }, []);
530
+
531
+ var state = React.useSyncExternalStore(
532
+ (listener) => modelRef.current.subscribe(listener),
533
+ () => modelRef.current.getSnapshot()
534
+ );
535
+ var controller = modelRef.current;
250
536
 
251
537
  if (state.status !== 'ready') {
252
538
  return h('div', { className: 'spSw' },
@@ -254,62 +540,27 @@ window.__ModuleLoader__.load({
254
540
  h('p', { className: 'spSwIntro' }, t('hostUnavailable')));
255
541
  }
256
542
 
257
- var value = state.value || {};
258
- var rawDisabled = value[DISABLED_FIELD] || {};
259
- var legacyActive = Object.keys(rawDisabled).length === 0;
260
- var disabled = !legacyActive
261
- ? rawDisabled
262
- : Object.assign({}, value.modelDisabled || {}, value.userDisabled || {});
263
- var language = readLanguage(value);
264
- var langConfigured = language !== undefined;
265
- var langValue = langConfigured ? language : 'auto';
543
+ var disabled = state.disabled;
544
+ var language = state.language;
545
+ var langConfigured = state.langConfigured;
546
+ var langValue = state.langValue;
266
547
  var langOptions = [
267
548
  { value: 'zh', label: t('langZh') },
268
549
  { value: 'en', label: t('langEn') },
269
550
  { value: 'auto', label: t('langAuto') },
270
551
  ];
271
- var setLang = function (next) {
272
- if (next === 'auto') {
273
- submit(form, t, ['language'], 'enable', setPending, setFailures,
274
- [{ op: 'unset', path: [LANGUAGE_FIELD] }]);
275
- } else {
276
- submit(form, t, ['language'], 'enable', setPending, setFailures,
277
- [{ op: 'set', path: [LANGUAGE_FIELD], value: next }]);
278
- }
279
- };
280
- var writable = state.writable !== false && state.mode !== 'memory';
281
-
282
- var lower = keyword.trim().toLowerCase();
283
- /* 描述取词:按当前语言偏好取对应语言文本,两侧都参与搜索过滤。 */
284
- var skillText = function (skill) {
285
- var effective = language === undefined ? hostActive : language;
286
- return effective === 'en' && skill.descriptionEn ? skill.descriptionEn : skill.description;
287
- };
288
- var shown = lower === ''
289
- ? SKILL_CATALOG
290
- : SKILL_CATALOG.filter(function (skill) {
291
- var name = skill.name.toLowerCase();
292
- return name.indexOf(lower) >= 0
293
- || skill.description.toLowerCase().indexOf(lower) >= 0
294
- || (skill.descriptionEn || '').toLowerCase().indexOf(lower) >= 0;
295
- });
552
+ var writable = state.writable;
296
553
 
297
- var allNames = SKILL_CATALOG.map(function (skill) { return skill.name; });
298
- var batchEnable = function () {
299
- submit(form, t, allNames, 'enable', setPending, setFailures);
300
- };
301
- var batchDisable = function () {
302
- submit(form, t, allNames, 'disable', setPending, setFailures);
303
- };
554
+ var shown = controller.getVisibleSkills(hostActive);
304
555
 
305
556
  var rows = shown.map(function (skill) {
306
- var busy = !!pending[skill.name] || !writable;
307
- var failure = failures[skill.name];
557
+ var busy = !!state.pending[skill.name] || !writable;
558
+ var failure = state.failures[skill.name];
308
559
  var on = !isBlocked(disabled, skill.name);
309
560
  return h('li', { key: skill.name, className: 'spSwItem' },
310
561
  h('div', { className: 'spSwMain' },
311
562
  h('div', { className: 'spSwName' }, skill.name),
312
- h('p', { className: 'spSwDesc' }, skillText(skill)),
563
+ h('p', { className: 'spSwDesc' }, skill.displayText),
313
564
  failure ? h('p', { className: 'spSwErr', role: 'alert' }, failure) : null),
314
565
  h('div', { className: 'spSwSwitch' },
315
566
  h('span', { className: 'spSwSwitchLabel' }, t('invocable')),
@@ -319,7 +570,7 @@ window.__ModuleLoader__.load({
319
570
  label: t('invocable') + ' ' + skill.name,
320
571
  title: t('invocableHint'),
321
572
  onChange: function (next) {
322
- submit(form, t, [skill.name], next ? 'enable' : 'disable', setPending, setFailures, null, legacyActive ? disabled : null);
573
+ controller.toggle(skill.name, next);
323
574
  },
324
575
  })));
325
576
  });
@@ -334,13 +585,13 @@ window.__ModuleLoader__.load({
334
585
  label: t('langTitle'),
335
586
  value: langValue,
336
587
  options: langOptions,
337
- disabled: !writable || !!pending['language'],
338
- onChange: setLang,
588
+ disabled: !writable || !!state.pending['language'],
589
+ onChange: function (next) { controller.setLanguage(next); },
339
590
  }),
340
591
  !langConfigured
341
592
  ? h('p', { className: 'spSwLangNote' }, t('langUnsetHint', { lang: t(hostActive === 'en' ? 'langEn' : 'langZh') }))
342
593
  : h('p', { className: 'spSwLangNote' }, t('langNote')),
343
- failures['language'] ? h('span', { className: 'spSwLangFailure', role: 'alert' }, failures['language']) : null),
594
+ state.failures['language'] ? h('span', { className: 'spSwLangFailure', role: 'alert' }, state.failures['language']) : null),
344
595
 
345
596
  h('div', { className: 'spSwBar' },
346
597
  h(P.Button, {
@@ -348,29 +599,29 @@ window.__ModuleLoader__.load({
348
599
  size: 'sm',
349
600
  disabled: !writable,
350
601
  title: t('resetHint'),
351
- onClick: batchEnable,
602
+ onClick: function () { controller.enableAll(); },
352
603
  }, t('enableAll')),
353
604
  h(P.Button, {
354
605
  variant: 'outline',
355
606
  size: 'sm',
356
607
  disabled: !writable,
357
608
  title: t('disableAllHint'),
358
- onClick: batchDisable,
609
+ onClick: function () { controller.disableAll(); },
359
610
  }, t('disableAll')),
360
611
  h(P.Button, {
361
612
  variant: 'ghost',
362
613
  size: 'sm',
363
614
  disabled: !writable,
364
615
  title: t('resetHint'),
365
- onClick: batchEnable,
616
+ onClick: function () { controller.resetAll(); },
366
617
  }, t('resetAll')),
367
618
  h(P.Input, {
368
619
  className: 'spSwSearch',
369
620
  type: 'search',
370
- value: keyword,
621
+ value: state.keyword,
371
622
  placeholder: t('search'),
372
623
  'aria-label': t('search'),
373
- onChange: function (event) { setKeyword(event.target.value); },
624
+ onChange: function (event) { controller.setKeyword(event.target.value); },
374
625
  })),
375
626
  shown.length === 0
376
627
  ? h('p', { className: 'spSwEmpty' }, t('empty'))
@@ -421,6 +672,8 @@ window.__ModuleLoader__.load({
421
672
 
422
673
  exports.apply = apply;
423
674
  exports.inject = ['slots', 'configForms', 'locale'];
675
+ exports.SwitchPanelModel = SwitchPanelModel;
676
+ exports.SKILL_CATALOG = SKILL_CATALOG;
424
677
  return module.exports;
425
678
  },
426
679
  });
@@ -11,7 +11,7 @@ import { SkillCatalog } from './catalog.js';
11
11
  import { SkillDocument } from './document.js';
12
12
  export { SkillCatalog, EXPECTED_SKILL_COUNT, type SpecificationReport } from './catalog.js';
13
13
  export { SkillDocument, type SpecificationTestResult } from './document.js';
14
- export { SkillSwitches, applySwitches, readSwitches } from './switches.js';
14
+ export { SkillSwitches, applySwitches, extractCleanDisabled, extractCleanLanguage, extractCleanSwitches, isConfigCorrupted, readSwitches, type CleanSwitchesExtraction, } from './switches.js';
15
15
  declare module '@deepseek-ai/cordis' {
16
16
  interface Events {
17
17
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"superpowers.d.ts","sourceRoot":"","sources":["../src/superpowers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAQ5D,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAI7C,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAC3F,OAAO,EAAE,aAAa,EAAE,KAAK,uBAAuB,EAAE,MAAM,eAAe,CAAA;AAC3E,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAQ1E,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,MAAM;QACd;;;;WAIG;QACH,wBAAwB,CAAC,KAAK,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,GAAG,IAAI,CAAA;QACrE;;;WAGG;QACH,wBAAwB,IAAI,IAAI,CAAA;KACjC;CACF;AAMD,eAAO,MAAM,MAAM,EAmC0C,MAAM,CAAC,MAAM,CAAC,CAAA;AAE3E,MAAM,WAAW,MAAM;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wDAAwD;IACxD,QAAQ,EAAE,QAAQ,CAAC,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;IAC3C,2CAA2C;IAC3C,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAC3C,wCAAwC;IACxC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAChD,kCAAkC;IAClC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CAChD;AAMD,eAAO,MAAM,IAAI,gBAAgB,CAAA;AACjC,eAAO,MAAM,MAAM,qBAAsB,CAAA;AA8GzC,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CA6CxD;;;;;;;;;AAED,wBAA2E"}
1
+ {"version":3,"file":"superpowers.d.ts","sourceRoot":"","sources":["../src/superpowers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAQ5D,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAS7C,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAC3F,OAAO,EAAE,aAAa,EAAE,KAAK,uBAAuB,EAAE,MAAM,eAAe,CAAA;AAC3E,OAAO,EACL,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,KAAK,uBAAuB,GAC7B,MAAM,eAAe,CAAA;AAQtB,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,MAAM;QACd;;;;WAIG;QACH,wBAAwB,CAAC,KAAK,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,GAAG,IAAI,CAAA;QACrE;;;WAGG;QACH,wBAAwB,IAAI,IAAI,CAAA;KACjC;CACF;AAMD,eAAO,MAAM,MAAM,EAyC0C,MAAM,CAAC,MAAM,CAAC,CAAA;AAE3E,MAAM,WAAW,MAAM;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wDAAwD;IACxD,QAAQ,EAAE,QAAQ,CAAC,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;IAC3C,2CAA2C;IAC3C,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAC3C,wCAAwC;IACxC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAChD,kCAAkC;IAClC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CAChD;AAMD,eAAO,MAAM,IAAI,gBAAgB,CAAA;AACjC,eAAO,MAAM,MAAM,qBAAsB,CAAA;AA4GzC,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CA6CxD;;;;;;;;;AAED,wBAA2E"}