dsh-plugin-effort-declare 0.1.1 → 0.1.3
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/CONTRIBUTING.en.md +5 -1
- package/CONTRIBUTING.md +5 -1
- package/INSTALL.en.md +1 -1
- package/INSTALL.md +1 -1
- package/README.en.md +8 -7
- package/README.md +8 -7
- package/lib/client.js +389 -65
- package/lib/client.js.map +1 -1
- package/lib/types/client/EffortDeclareSection.d.ts +12 -2
- package/lib/types/client/EffortDeclareSection.d.ts.map +1 -1
- package/lib/types/client/build-info.d.ts +2 -0
- package/lib/types/client/build-info.d.ts.map +1 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/load-drafts.d.ts +36 -6
- package/lib/types/client/load-drafts.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +1 -1
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/core/attribution.d.ts +13 -0
- package/lib/types/core/attribution.d.ts.map +1 -0
- package/lib/types/core/catalog.d.ts +5 -3
- package/lib/types/core/catalog.d.ts.map +1 -1
- package/lib/types/core/drafts.d.ts +34 -2
- package/lib/types/core/drafts.d.ts.map +1 -1
- package/lib/types/core/efforts.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/README.en.md +1 -1
- package/src/README.md +1 -1
- package/src/client/EffortDeclareSection.tsx +158 -46
- package/src/client/README.en.md +5 -3
- package/src/client/README.md +5 -3
- package/src/client/build-info.ts +12 -0
- package/src/client/effort-declare.module.css +8 -0
- package/src/client/globals.d.ts +5 -0
- package/src/client/index.ts +14 -9
- package/src/client/load-drafts.ts +124 -8
- package/src/client/locales.ts +3 -0
- package/src/core/README.en.md +4 -3
- package/src/core/README.md +4 -3
- package/src/core/attribution.ts +24 -0
- package/src/core/catalog.ts +5 -3
- package/src/core/drafts.ts +151 -4
- package/src/core/efforts.ts +4 -1
package/lib/client.js
CHANGED
|
@@ -12,9 +12,11 @@ window.__ModuleLoader__.load({
|
|
|
12
12
|
*
|
|
13
13
|
* Levels match `@deepseek-ai/dsh-llm-pi-ai` catalog.ts `THINKING_LEVELS`.
|
|
14
14
|
* Formats match `SUPPORTED_THINKING_FORMATS` in the same file (rc.8).
|
|
15
|
-
* Tests pin these lists against
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* Tests pin these lists against a checked-in schema fixture
|
|
16
|
+
* (`tests/fixtures/pi-ai-thinking-format-union.ts`) and the local level
|
|
17
|
+
* whitelist. The settings page never offers the handwritten thinkingFormat
|
|
18
|
+
* list as writable choices — only the live schema union, plus a stored
|
|
19
|
+
* value that the union omitted.
|
|
18
20
|
*/
|
|
19
21
|
/** Selectable reasoning levels, in pi-ai escalation order. */
|
|
20
22
|
const THINKING_LEVELS = [
|
|
@@ -156,6 +158,14 @@ window.__ModuleLoader__.load({
|
|
|
156
158
|
* Route-card draft merge: user-layer slices, namespace revision, dirty preserve.
|
|
157
159
|
* No React — settings UI and tests share these helpers.
|
|
158
160
|
*/
|
|
161
|
+
/** JSON-stable equality matching pathOps (key order included). */
|
|
162
|
+
function sliceEqual(left, right) {
|
|
163
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
164
|
+
}
|
|
165
|
+
/** Whether two settings slices differ. */
|
|
166
|
+
function sliceChanged(before, after) {
|
|
167
|
+
return !sliceEqual(before, after);
|
|
168
|
+
}
|
|
159
169
|
/** Build a draft from the stored user subtree (never from effective `value`). */
|
|
160
170
|
function routeDraftFromUserProfile(args) {
|
|
161
171
|
const { provider, displayName, settingsPath, revision, userProfile } = args;
|
|
@@ -210,9 +220,103 @@ window.__ModuleLoader__.load({
|
|
|
210
220
|
});
|
|
211
221
|
});
|
|
212
222
|
}
|
|
223
|
+
function modelRowId(row) {
|
|
224
|
+
return String(row.id);
|
|
225
|
+
}
|
|
226
|
+
function indexById(rows) {
|
|
227
|
+
const map = /* @__PURE__ */ new Map();
|
|
228
|
+
for (const row of rows) {
|
|
229
|
+
const id = modelRowId(row);
|
|
230
|
+
if (!map.has(id)) map.set(id, row);
|
|
231
|
+
}
|
|
232
|
+
return map;
|
|
233
|
+
}
|
|
234
|
+
function effortsPresence(row) {
|
|
235
|
+
if (row === void 0 || !Object.hasOwn(row, "reasoningEfforts")) return {
|
|
236
|
+
present: false,
|
|
237
|
+
value: void 0
|
|
238
|
+
};
|
|
239
|
+
return {
|
|
240
|
+
present: true,
|
|
241
|
+
value: row.reasoningEfforts
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
function effortsEqual(left, right) {
|
|
245
|
+
if (left.present !== right.present) return false;
|
|
246
|
+
if (!left.present) return true;
|
|
247
|
+
return sliceEqual(left.value, right.value);
|
|
248
|
+
}
|
|
249
|
+
function overlayLocalEfforts(incomingRow, prevRow) {
|
|
250
|
+
const next = structuredClone(incomingRow);
|
|
251
|
+
if (Object.hasOwn(prevRow, "reasoningEfforts")) next.reasoningEfforts = structuredClone(prevRow.reasoningEfforts);
|
|
252
|
+
else delete next.reasoningEfforts;
|
|
253
|
+
return next;
|
|
254
|
+
}
|
|
255
|
+
function objectKeyChanged(left, right, key) {
|
|
256
|
+
const leftHas = Object.hasOwn(left, key);
|
|
257
|
+
if (leftHas !== Object.hasOwn(right, key)) return true;
|
|
258
|
+
if (!leftHas) return false;
|
|
259
|
+
return sliceChanged(left[key], right[key]);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Membership follows the latest user-layer models list (Models page add/delete).
|
|
263
|
+
* Local unsaved `reasoningEfforts` (including a cleared key) overlay by id.
|
|
264
|
+
*/
|
|
265
|
+
function mergeModelsById(args) {
|
|
266
|
+
const prevById = indexById(args.prevModels);
|
|
267
|
+
const prevOrigById = indexById(args.prevOriginal);
|
|
268
|
+
const incomingOrigById = indexById(args.incomingOriginal);
|
|
269
|
+
const incomingIds = new Set(args.incomingModels.map(modelRowId));
|
|
270
|
+
let conflicted = false;
|
|
271
|
+
const models = args.incomingModels.map((incomingRow) => {
|
|
272
|
+
const id = modelRowId(incomingRow);
|
|
273
|
+
const prevRow = prevById.get(id);
|
|
274
|
+
if (prevRow === void 0) return structuredClone(incomingRow);
|
|
275
|
+
const prevOrig = prevOrigById.get(id);
|
|
276
|
+
if (!!effortsEqual(effortsPresence(prevRow), effortsPresence(prevOrig))) return structuredClone(incomingRow);
|
|
277
|
+
const incomingOrig = incomingOrigById.get(id);
|
|
278
|
+
if (!effortsEqual(effortsPresence(prevOrig), effortsPresence(incomingOrig))) conflicted = true;
|
|
279
|
+
return overlayLocalEfforts(incomingRow, prevRow);
|
|
280
|
+
});
|
|
281
|
+
for (const [id, prevRow] of prevById) {
|
|
282
|
+
if (incomingIds.has(id)) continue;
|
|
283
|
+
const prevOrig = prevOrigById.get(id);
|
|
284
|
+
if (effortsEqual(effortsPresence(prevRow), effortsPresence(prevOrig))) continue;
|
|
285
|
+
if (!effortsEqual(effortsPresence(prevOrig), effortsPresence(incomingOrigById.get(id)))) conflicted = true;
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
models,
|
|
289
|
+
conflicted
|
|
290
|
+
};
|
|
291
|
+
}
|
|
213
292
|
/**
|
|
214
|
-
*
|
|
215
|
-
*
|
|
293
|
+
* Three-way compat merge: locally changed keys stay local; everything else
|
|
294
|
+
* follows incoming. Conflict only when a locally dirty key also moved in originals.
|
|
295
|
+
*/
|
|
296
|
+
function mergeCompat(args) {
|
|
297
|
+
if (!sliceChanged(args.prev, args.prevOriginal)) return {
|
|
298
|
+
compat: cloneObject(args.incoming),
|
|
299
|
+
conflicted: false
|
|
300
|
+
};
|
|
301
|
+
const compat = cloneObject(args.incoming);
|
|
302
|
+
let conflicted = false;
|
|
303
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(args.prev), ...Object.keys(args.prevOriginal)]);
|
|
304
|
+
for (const key of keys) {
|
|
305
|
+
if (!objectKeyChanged(args.prev, args.prevOriginal, key)) continue;
|
|
306
|
+
if (objectKeyChanged(args.prevOriginal, args.incomingOriginal, key)) conflicted = true;
|
|
307
|
+
if (Object.hasOwn(args.prev, key)) compat[key] = structuredClone(args.prev[key]);
|
|
308
|
+
else delete compat[key];
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
compat,
|
|
312
|
+
conflicted
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Apply a freshly loaded table. Membership and metadata follow incoming;
|
|
317
|
+
* unsaved reasoningEfforts / dirty compat keys overlay by id. Conflict only
|
|
318
|
+
* when a locally dirty field also changed in originals (revision-only bumps
|
|
319
|
+
* and sibling-card saves do not warn).
|
|
216
320
|
*/
|
|
217
321
|
function mergeLoadedDrafts(current, incoming, options) {
|
|
218
322
|
const currentByProvider = new Map(current.map((draft) => [draft.provider, draft]));
|
|
@@ -221,13 +325,27 @@ window.__ModuleLoader__.load({
|
|
|
221
325
|
drafts: incoming.map((next) => {
|
|
222
326
|
const prev = currentByProvider.get(next.provider);
|
|
223
327
|
if (prev === void 0 || !options.preserveDirty || !draftDirty(prev)) return next;
|
|
224
|
-
|
|
328
|
+
const modelsMerge = mergeModelsById({
|
|
329
|
+
prevModels: prev.models,
|
|
330
|
+
prevOriginal: prev.originalModels,
|
|
331
|
+
incomingModels: next.models,
|
|
332
|
+
incomingOriginal: next.originalModels
|
|
333
|
+
});
|
|
334
|
+
const compatMerge = mergeCompat({
|
|
335
|
+
prev: prev.compat,
|
|
336
|
+
prevOriginal: prev.originalCompat,
|
|
337
|
+
incoming: next.compat,
|
|
338
|
+
incomingOriginal: next.originalCompat
|
|
339
|
+
});
|
|
340
|
+
if (modelsMerge.conflicted || compatMerge.conflicted) conflicted.push(next.provider);
|
|
225
341
|
return {
|
|
226
|
-
|
|
342
|
+
provider: next.provider,
|
|
227
343
|
displayName: next.displayName,
|
|
228
344
|
settingsPath: next.settingsPath,
|
|
229
345
|
revision: next.revision,
|
|
346
|
+
models: modelsMerge.models,
|
|
230
347
|
originalModels: cloneModels(next.originalModels),
|
|
348
|
+
compat: compatMerge.compat,
|
|
231
349
|
originalCompat: cloneObject(next.originalCompat),
|
|
232
350
|
compatPresent: next.compatPresent
|
|
233
351
|
};
|
|
@@ -271,7 +389,10 @@ window.__ModuleLoader__.load({
|
|
|
271
389
|
const next = { ...efforts };
|
|
272
390
|
delete next.off;
|
|
273
391
|
if (mode === "empty") next.off = null;
|
|
274
|
-
else if (mode === "value")
|
|
392
|
+
else if (mode === "value") {
|
|
393
|
+
const trimmed = value.trim();
|
|
394
|
+
next.off = trimmed.length > 0 ? trimmed : "none";
|
|
395
|
+
}
|
|
275
396
|
return next;
|
|
276
397
|
}
|
|
277
398
|
/** Whether a thinking level (other than Off) is currently declared. */
|
|
@@ -410,20 +531,104 @@ window.__ModuleLoader__.load({
|
|
|
410
531
|
return validateReasoningEfforts(row.reasoningEfforts);
|
|
411
532
|
}
|
|
412
533
|
//#endregion
|
|
534
|
+
//#region src/core/attribution.ts
|
|
535
|
+
/**
|
|
536
|
+
* Plugin footer attribution. Version and end-year are frozen into the client
|
|
537
|
+
* bundle at pack time; this module only formats the line.
|
|
538
|
+
*/
|
|
539
|
+
/** First publication year (LICENSE). Not the user's wall clock. */
|
|
540
|
+
const COPYRIGHT_FROM = 2026;
|
|
541
|
+
const COPYRIGHT_HOLDER = "Stardust";
|
|
542
|
+
/**
|
|
543
|
+
* `0.1.2 © 2026 Stardust` or `0.1.2 © 2026–2027 Stardust`.
|
|
544
|
+
* Throws if version is empty or `to < from` — a bad stamp must not render.
|
|
545
|
+
*/
|
|
546
|
+
function formatAttribution(version, from, to) {
|
|
547
|
+
if (version.trim() === "") throw new Error("plugin version must be a non-empty string");
|
|
548
|
+
if (!Number.isInteger(from) || !Number.isInteger(to) || to < from) throw new Error(`invalid copyright range: ${String(from)}\u2013${String(to)}`);
|
|
549
|
+
return `${version} \u00a9 ${to === from ? String(from) : `${String(from)}\u2013${String(to)}`} ${COPYRIGHT_HOLDER}`;
|
|
550
|
+
}
|
|
551
|
+
//#endregion
|
|
552
|
+
//#region src/client/build-info.ts
|
|
553
|
+
/**
|
|
554
|
+
* Footer line frozen into the client bundle. Do not read the clock or
|
|
555
|
+
* package.json at DSH startup — host apply is empty and the settings page
|
|
556
|
+
* runs in the browser.
|
|
557
|
+
*/
|
|
558
|
+
const PLUGIN_FOOTER_TEXT = formatAttribution("0.1.3", COPYRIGHT_FROM, 2026);
|
|
559
|
+
//#endregion
|
|
413
560
|
//#region src/client/load-drafts.ts
|
|
414
561
|
function schemaDefaultString(node) {
|
|
415
562
|
if (!isPlainObject(node) || !isPlainObject(node.meta)) return void 0;
|
|
416
563
|
return typeof node.meta.default === "string" ? node.meta.default : void 0;
|
|
417
564
|
}
|
|
565
|
+
/** Namespace revision on a describe snapshot, if that row exists. */
|
|
566
|
+
function namespaceRevision(snapshot, ns) {
|
|
567
|
+
return snapshot.view?.namespaces.find((view) => view.ns === ns)?.revision;
|
|
568
|
+
}
|
|
418
569
|
/**
|
|
419
|
-
*
|
|
420
|
-
*
|
|
421
|
-
*
|
|
422
|
-
* `formats` is the live schema union only. Empty means the dropdown has no
|
|
423
|
-
* writable choices (stored values stay visible via `thinkingFormatChoices`).
|
|
570
|
+
* True when `incoming` is the Host echo of a mutate this page already folded,
|
|
571
|
+
* or an older revision the snapshot has already passed. `echoed` is undefined
|
|
572
|
+
* until the first successful write.
|
|
424
573
|
*/
|
|
425
|
-
|
|
426
|
-
|
|
574
|
+
function isOwnDocumentEcho(echoed, incoming) {
|
|
575
|
+
return echoed !== void 0 && incoming <= echoed;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* After a preserve-dirty reload: conflicted cards get a conflict notice;
|
|
579
|
+
* live cards drop leftover conflict/error; saved notices stay; gone cards drop.
|
|
580
|
+
*/
|
|
581
|
+
function foldReloadNotices(current, args) {
|
|
582
|
+
const live = new Set(args.liveProviders);
|
|
583
|
+
const conflicted = new Set(args.conflicted);
|
|
584
|
+
const next = {};
|
|
585
|
+
for (const [provider, notice] of Object.entries(current)) {
|
|
586
|
+
if (!live.has(provider)) continue;
|
|
587
|
+
if (conflicted.has(provider)) continue;
|
|
588
|
+
if (notice.kind === "conflict" || notice.kind === "error") continue;
|
|
589
|
+
next[provider] = notice;
|
|
590
|
+
}
|
|
591
|
+
for (const provider of args.conflicted) next[provider] = args.conflictNotice;
|
|
592
|
+
return next;
|
|
593
|
+
}
|
|
594
|
+
function waitUntil(describe, predicate, signal) {
|
|
595
|
+
if (signal?.aborted) return Promise.resolve(false);
|
|
596
|
+
if (predicate()) return Promise.resolve(true);
|
|
597
|
+
return new Promise((resolve) => {
|
|
598
|
+
let settled = false;
|
|
599
|
+
const finish = (ok) => {
|
|
600
|
+
if (settled) return;
|
|
601
|
+
settled = true;
|
|
602
|
+
stop();
|
|
603
|
+
signal?.removeEventListener("abort", onAbort);
|
|
604
|
+
resolve(ok);
|
|
605
|
+
};
|
|
606
|
+
const onAbort = () => {
|
|
607
|
+
finish(false);
|
|
608
|
+
};
|
|
609
|
+
const stop = describe.subscribe(() => {
|
|
610
|
+
if (predicate()) finish(true);
|
|
611
|
+
});
|
|
612
|
+
signal?.addEventListener("abort", onAbort);
|
|
613
|
+
if (predicate()) finish(true);
|
|
614
|
+
else if (signal?.aborted) finish(false);
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
/** Resolve when the mirror's namespace revision is at least `revision`, or abort. */
|
|
618
|
+
async function waitForNamespaceRevision(describe, ns, revision, signal) {
|
|
619
|
+
return await waitUntil(describe, () => {
|
|
620
|
+
const current = namespaceRevision(describe.getSnapshot(), ns);
|
|
621
|
+
return current !== void 0 && current >= revision;
|
|
622
|
+
}, signal) ? "matched" : "aborted";
|
|
623
|
+
}
|
|
624
|
+
/** Resolve when the namespace revision differs from `previous`, or abort. */
|
|
625
|
+
async function waitForNamespaceRevisionChange(describe, ns, previous, signal) {
|
|
626
|
+
return await waitUntil(describe, () => {
|
|
627
|
+
const current = namespaceRevision(describe.getSnapshot(), ns);
|
|
628
|
+
return current !== void 0 && current !== previous;
|
|
629
|
+
}, signal) ? "changed" : "aborted";
|
|
630
|
+
}
|
|
631
|
+
async function assembleDrafts(api, describe, schema) {
|
|
427
632
|
const mirrored = describe.getSnapshot();
|
|
428
633
|
if (mirrored.view === void 0) return {
|
|
429
634
|
writable: false,
|
|
@@ -474,6 +679,14 @@ window.__ModuleLoader__.load({
|
|
|
474
679
|
drafts
|
|
475
680
|
};
|
|
476
681
|
}
|
|
682
|
+
/**
|
|
683
|
+
* `ensure`: first paint / idle recovery (official ensure only reads from idle).
|
|
684
|
+
* `snapshot`: refresh after the mirror revision already moved — do not ensure.
|
|
685
|
+
*/
|
|
686
|
+
async function loadDrafts(api, describe, schema, mode = "ensure") {
|
|
687
|
+
if (mode === "ensure") await describe.ensure();
|
|
688
|
+
return assembleDrafts(api, describe, schema);
|
|
689
|
+
}
|
|
477
690
|
//#endregion
|
|
478
691
|
//#region src/client/schema-ops.ts
|
|
479
692
|
/** Wrap a live settingsSchema service as plain callbacks. */
|
|
@@ -506,7 +719,7 @@ window.__ModuleLoader__.load({
|
|
|
506
719
|
}
|
|
507
720
|
//#endregion
|
|
508
721
|
//#region \0dsh-css:C:\Users\zimo\AppData\Roaming\io.github.hairyf.deepseek-harness-desktop\data\dsh\临时目录\dsh-plugin-effort-declare\src\client\effort-declare.module.css.mjs
|
|
509
|
-
const cssText = ".hYEBUa_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}.hYEBUa_title{color:var(--dsw-alias-label-primary);margin:0;font-size:16px;font-weight:500;line-height:24px}.hYEBUa_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}.hYEBUa_notice{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}.hYEBUa_savedNotice{color:var(--dsw-alias-state-success-primary);margin:0;font-size:12px;line-height:18px}.hYEBUa_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.hYEBUa_rows{flex-direction:column;gap:8px;margin:12px 0 0;padding:0;list-style:none;display:flex}.hYEBUa_rowCard{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;flex-direction:column;gap:12px;padding:12px 14px;display:flex}.hYEBUa_rowHead{align-items:baseline;gap:8px;display:flex}.hYEBUa_rowName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.hYEBUa_rowTag{border:1px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:1px 6px;font-size:11px;line-height:16px}.hYEBUa_compatSummary{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.hYEBUa_presetRow,.hYEBUa_actions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.hYEBUa_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.hYEBUa_primaryButton,.hYEBUa_secondaryButton{box-sizing:border-box;height:36px;font:inherit;cursor:pointer;border-radius:18px;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.hYEBUa_primaryButton{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border:none}.hYEBUa_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.hYEBUa_secondaryButton{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0}.hYEBUa_secondaryButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.hYEBUa_primaryButton:disabled,.hYEBUa_secondaryButton:disabled,.hYEBUa_linkButton:disabled,.hYEBUa_input:disabled{opacity:.4;cursor:default}.hYEBUa_primaryButton:focus-visible,.hYEBUa_secondaryButton:focus-visible,.hYEBUa_linkButton:focus-visible,.hYEBUa_input:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3);outline:none}.hYEBUa_linkButton{box-sizing:border-box;height:28px;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:14px;align-items:center;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.hYEBUa_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.hYEBUa_modelEntry{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:8px;padding:10px 0;display:flex}.hYEBUa_modelHead{flex-wrap:wrap;align-items:baseline;gap:8px;display:flex}.hYEBUa_modelId{font-size:13px;font-weight:500;line-height:20px}.hYEBUa_modelName{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.hYEBUa_levels{flex-wrap:wrap;gap:10px 14px;display:flex}.hYEBUa_level{align-items:center;gap:6px;font-size:12px;line-height:18px;display:inline-flex}.hYEBUa_wireRow{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.hYEBUa_input,.hYEBUa_selectInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);height:32px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:8px;padding:0 10px;font-size:13px}.hYEBUa_wireInput{width:7em}.hYEBUa_offGroup{flex-direction:column;gap:6px;display:flex}.hYEBUa_advanced{border-top:1px solid var(--dsw-alias-border-l2);padding-top:8px}.hYEBUa_advanced summary{cursor:pointer;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.hYEBUa_advancedBody{flex-direction:column;gap:10px;padding-top:10px;display:flex}.hYEBUa_check{align-items:flex-start;gap:8px;font-size:12px;line-height:18px;display:flex}";
|
|
722
|
+
const cssText = ".hYEBUa_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}.hYEBUa_title{color:var(--dsw-alias-label-primary);margin:0;font-size:16px;font-weight:500;line-height:24px}.hYEBUa_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}.hYEBUa_notice{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}.hYEBUa_savedNotice{color:var(--dsw-alias-state-success-primary);margin:0;font-size:12px;line-height:18px}.hYEBUa_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.hYEBUa_rows{flex-direction:column;gap:8px;margin:12px 0 0;padding:0;list-style:none;display:flex}.hYEBUa_rowCard{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;flex-direction:column;gap:12px;padding:12px 14px;display:flex}.hYEBUa_rowHead{align-items:baseline;gap:8px;display:flex}.hYEBUa_rowName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.hYEBUa_rowTag{border:1px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:1px 6px;font-size:11px;line-height:16px}.hYEBUa_compatSummary{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.hYEBUa_presetRow,.hYEBUa_actions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.hYEBUa_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.hYEBUa_primaryButton,.hYEBUa_secondaryButton{box-sizing:border-box;height:36px;font:inherit;cursor:pointer;border-radius:18px;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.hYEBUa_primaryButton{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border:none}.hYEBUa_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.hYEBUa_secondaryButton{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0}.hYEBUa_secondaryButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.hYEBUa_primaryButton:disabled,.hYEBUa_secondaryButton:disabled,.hYEBUa_linkButton:disabled,.hYEBUa_input:disabled{opacity:.4;cursor:default}.hYEBUa_primaryButton:focus-visible,.hYEBUa_secondaryButton:focus-visible,.hYEBUa_linkButton:focus-visible,.hYEBUa_input:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3);outline:none}.hYEBUa_linkButton{box-sizing:border-box;height:28px;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:14px;align-items:center;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.hYEBUa_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.hYEBUa_modelEntry{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:8px;padding:10px 0;display:flex}.hYEBUa_modelHead{flex-wrap:wrap;align-items:baseline;gap:8px;display:flex}.hYEBUa_modelId{font-size:13px;font-weight:500;line-height:20px}.hYEBUa_modelName{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.hYEBUa_levels{flex-wrap:wrap;gap:10px 14px;display:flex}.hYEBUa_level{align-items:center;gap:6px;font-size:12px;line-height:18px;display:inline-flex}.hYEBUa_wireRow{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.hYEBUa_input,.hYEBUa_selectInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);height:32px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:8px;padding:0 10px;font-size:13px}.hYEBUa_wireInput{width:7em}.hYEBUa_offGroup{flex-direction:column;gap:6px;display:flex}.hYEBUa_advanced{border-top:1px solid var(--dsw-alias-border-l2);padding-top:8px}.hYEBUa_advanced summary{cursor:pointer;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.hYEBUa_advancedBody{flex-direction:column;gap:10px;padding-top:10px;display:flex}.hYEBUa_check{align-items:flex-start;gap:8px;font-size:12px;line-height:18px;display:flex}.hYEBUa_footer{color:var(--dsw-alias-label-tertiary);opacity:.7;margin:16px 0 0;font-size:11px;line-height:16px}";
|
|
510
723
|
const cssTagId = "dsh-plugin-effort-declare/effort-declare.module.css";
|
|
511
724
|
var effort_declare_module_css_default = {
|
|
512
725
|
"actions": "hYEBUa_actions",
|
|
@@ -516,6 +729,7 @@ window.__ModuleLoader__.load({
|
|
|
516
729
|
"compatSummary": "hYEBUa_compatSummary",
|
|
517
730
|
"error": "hYEBUa_error",
|
|
518
731
|
"fieldLabel": "hYEBUa_fieldLabel",
|
|
732
|
+
"footer": "hYEBUa_footer",
|
|
519
733
|
"input": "hYEBUa_input",
|
|
520
734
|
"intro": "hYEBUa_intro",
|
|
521
735
|
"level": "hYEBUa_level",
|
|
@@ -670,10 +884,10 @@ window.__ModuleLoader__.load({
|
|
|
670
884
|
});
|
|
671
885
|
}
|
|
672
886
|
function RouteCard(props) {
|
|
673
|
-
const { draft, writable, busy,
|
|
887
|
+
const { draft, writable, busy, saveLocked, t, onChange } = props;
|
|
674
888
|
const noModels = draft.models.length === 0;
|
|
675
889
|
const editDisabled = !writable || busy || noModels;
|
|
676
|
-
const
|
|
890
|
+
const saveDisabled = saveLocked || noModels;
|
|
677
891
|
const formats = thinkingFormatChoices(props.formats, draft.compat.thinkingFormat);
|
|
678
892
|
const summary = compatSummary(draft.compat);
|
|
679
893
|
const sameWire = draft.compat.supportsReasoningEffort === false;
|
|
@@ -857,7 +1071,7 @@ window.__ModuleLoader__.load({
|
|
|
857
1071
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
858
1072
|
type: "button",
|
|
859
1073
|
className: effort_declare_module_css_default.primaryButton,
|
|
860
|
-
disabled:
|
|
1074
|
+
disabled: saveDisabled || !dirty || clientError !== void 0,
|
|
861
1075
|
onClick: () => {
|
|
862
1076
|
props.onSave(draft);
|
|
863
1077
|
},
|
|
@@ -881,40 +1095,92 @@ window.__ModuleLoader__.load({
|
|
|
881
1095
|
const [notices, setNotices] = (0, react.useState)({});
|
|
882
1096
|
const generationRef = (0, react.useRef)(0);
|
|
883
1097
|
const draftsRef = (0, react.useRef)(drafts);
|
|
1098
|
+
const echoedRevisionRef = (0, react.useRef)(void 0);
|
|
1099
|
+
const pendingRevisionRef = (0, react.useRef)(void 0);
|
|
1100
|
+
const busyRouteRef = (0, react.useRef)(null);
|
|
1101
|
+
const abortRef = (0, react.useRef)(null);
|
|
884
1102
|
draftsRef.current = drafts;
|
|
885
|
-
const
|
|
1103
|
+
const applyDrafts = (next) => {
|
|
1104
|
+
const resolved = typeof next === "function" ? next(draftsRef.current) : next;
|
|
1105
|
+
draftsRef.current = resolved;
|
|
1106
|
+
setDrafts(resolved);
|
|
1107
|
+
};
|
|
1108
|
+
const snapshotMode = () => describe === void 0 || describe.getSnapshot().status === "idle" ? "ensure" : "snapshot";
|
|
1109
|
+
const beginGeneration = () => {
|
|
1110
|
+
abortRef.current?.abort();
|
|
1111
|
+
const abort = new AbortController();
|
|
1112
|
+
abortRef.current = abort;
|
|
1113
|
+
return {
|
|
1114
|
+
generation: nextGeneration(generationRef),
|
|
1115
|
+
signal: abort.signal
|
|
1116
|
+
};
|
|
1117
|
+
};
|
|
1118
|
+
const failGeneration = (generation, failure) => {
|
|
1119
|
+
if (!generationIsCurrent(generationRef, generation)) return;
|
|
1120
|
+
setStatus("error");
|
|
1121
|
+
setError(failure instanceof Error ? failure.message : t("loadError"));
|
|
1122
|
+
};
|
|
1123
|
+
const settleReload = (generation, preserveDirty, result) => {
|
|
1124
|
+
if (!generationIsCurrent(generationRef, generation)) return;
|
|
1125
|
+
setWritable(result.writable);
|
|
1126
|
+
setFormats(result.formats);
|
|
1127
|
+
if (result.error !== void 0) {
|
|
1128
|
+
setStatus("error");
|
|
1129
|
+
setError(result.error);
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
const merged = mergeLoadedDrafts(draftsRef.current, result.drafts, { preserveDirty });
|
|
1133
|
+
applyDrafts(merged.drafts);
|
|
1134
|
+
setNotices((current) => foldReloadNotices(current, {
|
|
1135
|
+
conflicted: merged.conflicted,
|
|
1136
|
+
conflictNotice: {
|
|
1137
|
+
kind: "conflict",
|
|
1138
|
+
text: t("dirtyConflict")
|
|
1139
|
+
},
|
|
1140
|
+
liveProviders: merged.drafts.map((draft) => draft.provider)
|
|
1141
|
+
}));
|
|
1142
|
+
setStatus("ready");
|
|
1143
|
+
};
|
|
1144
|
+
const loadSnapshotThenSettle = async (generation, preserveDirty) => {
|
|
1145
|
+
if (api === void 0 || describe === void 0 || schema === void 0) return;
|
|
1146
|
+
if (!generationIsCurrent(generationRef, generation)) return;
|
|
1147
|
+
try {
|
|
1148
|
+
const result = await loadDrafts(api, describe, schema, "snapshot");
|
|
1149
|
+
settleReload(generation, preserveDirty, result);
|
|
1150
|
+
} catch (failure) {
|
|
1151
|
+
failGeneration(generation, failure);
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
1154
|
+
const reload = (0, react.useCallback)((preserveDirty, mode = "ensure") => {
|
|
886
1155
|
if (api === void 0 || describe === void 0 || schema === void 0) {
|
|
887
1156
|
setStatus("error");
|
|
888
1157
|
setError(t("loadError"));
|
|
889
1158
|
return;
|
|
890
1159
|
}
|
|
891
|
-
const generation =
|
|
892
|
-
setStatus("loading");
|
|
1160
|
+
const { generation } = beginGeneration();
|
|
1161
|
+
if (draftsRef.current.length === 0) setStatus("loading");
|
|
893
1162
|
setError("");
|
|
894
|
-
loadDrafts(api, describe, schema).then((result) => {
|
|
895
|
-
|
|
896
|
-
setWritable(result.writable);
|
|
897
|
-
setFormats(result.formats);
|
|
898
|
-
if (result.error !== void 0) {
|
|
899
|
-
setStatus("error");
|
|
900
|
-
setError(result.error);
|
|
901
|
-
return;
|
|
902
|
-
}
|
|
903
|
-
const merged = mergeLoadedDrafts(draftsRef.current, result.drafts, { preserveDirty });
|
|
904
|
-
setDrafts(merged.drafts);
|
|
905
|
-
if (merged.conflicted.length > 0) setNotices((current) => {
|
|
906
|
-
const next = { ...current };
|
|
907
|
-
for (const provider of merged.conflicted) next[provider] = {
|
|
908
|
-
kind: "conflict",
|
|
909
|
-
text: t("dirtyConflict")
|
|
910
|
-
};
|
|
911
|
-
return next;
|
|
912
|
-
});
|
|
913
|
-
setStatus("ready");
|
|
1163
|
+
loadDrafts(api, describe, schema, mode).then((result) => {
|
|
1164
|
+
settleReload(generation, preserveDirty, result);
|
|
914
1165
|
}, (failure) => {
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1166
|
+
failGeneration(generation, failure);
|
|
1167
|
+
});
|
|
1168
|
+
}, [
|
|
1169
|
+
api,
|
|
1170
|
+
describe,
|
|
1171
|
+
schema,
|
|
1172
|
+
t
|
|
1173
|
+
]);
|
|
1174
|
+
const refreshAtRevision = (0, react.useCallback)((revision, preserveDirty) => {
|
|
1175
|
+
if (api === void 0 || describe === void 0 || schema === void 0) return;
|
|
1176
|
+
const { generation, signal } = beginGeneration();
|
|
1177
|
+
if (draftsRef.current.length === 0) setStatus("loading");
|
|
1178
|
+
setError("");
|
|
1179
|
+
waitForNamespaceRevision(describe, LLM_PI_AI_NS, revision, signal).then((outcome) => {
|
|
1180
|
+
if (outcome === "aborted" || !generationIsCurrent(generationRef, generation)) return;
|
|
1181
|
+
return loadSnapshotThenSettle(generation, preserveDirty);
|
|
1182
|
+
}, (failure) => {
|
|
1183
|
+
failGeneration(generation, failure);
|
|
918
1184
|
});
|
|
919
1185
|
}, [
|
|
920
1186
|
api,
|
|
@@ -922,15 +1188,46 @@ window.__ModuleLoader__.load({
|
|
|
922
1188
|
schema,
|
|
923
1189
|
t
|
|
924
1190
|
]);
|
|
1191
|
+
const flushPendingSettings = (refresh) => {
|
|
1192
|
+
const pending = pendingRevisionRef.current;
|
|
1193
|
+
pendingRevisionRef.current = void 0;
|
|
1194
|
+
if (pending === void 0) return;
|
|
1195
|
+
if (isOwnDocumentEcho(echoedRevisionRef.current, pending)) return;
|
|
1196
|
+
refresh(pending, true);
|
|
1197
|
+
};
|
|
925
1198
|
(0, react.useEffect)(() => {
|
|
926
|
-
reload(false);
|
|
1199
|
+
reload(false, "ensure");
|
|
927
1200
|
}, [reload]);
|
|
1201
|
+
(0, react.useEffect)(() => () => {
|
|
1202
|
+
abortRef.current?.abort();
|
|
1203
|
+
nextGeneration(generationRef);
|
|
1204
|
+
}, []);
|
|
928
1205
|
(0, react.useEffect)(() => {
|
|
929
1206
|
if (props.subscribeInvalidate === void 0) return void 0;
|
|
930
|
-
return props.subscribeInvalidate((
|
|
931
|
-
if (source === "
|
|
1207
|
+
return props.subscribeInvalidate((event) => {
|
|
1208
|
+
if (event.source === "writable") {
|
|
1209
|
+
const view = describe?.getSnapshot().view;
|
|
1210
|
+
if (view !== void 0) setWritable(view.writable);
|
|
1211
|
+
return;
|
|
1212
|
+
}
|
|
1213
|
+
if (event.source === "settings") {
|
|
1214
|
+
if (busyRouteRef.current !== null) {
|
|
1215
|
+
pendingRevisionRef.current = event.revision;
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
if (isOwnDocumentEcho(echoedRevisionRef.current, event.revision)) return;
|
|
1219
|
+
refreshAtRevision(event.revision, true);
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1222
|
+
if (event.source === "directory") reload(true, snapshotMode());
|
|
1223
|
+
if (event.source === "reset") reload(true, "ensure");
|
|
932
1224
|
});
|
|
933
|
-
}, [
|
|
1225
|
+
}, [
|
|
1226
|
+
describe,
|
|
1227
|
+
props.subscribeInvalidate,
|
|
1228
|
+
refreshAtRevision,
|
|
1229
|
+
reload
|
|
1230
|
+
]);
|
|
934
1231
|
const patchNotice = (provider, notice) => {
|
|
935
1232
|
setNotices((current) => {
|
|
936
1233
|
const copy = { ...current };
|
|
@@ -941,7 +1238,13 @@ window.__ModuleLoader__.load({
|
|
|
941
1238
|
};
|
|
942
1239
|
const save = async (draft) => {
|
|
943
1240
|
if (api === void 0 || describe === void 0 || schema === void 0) return;
|
|
944
|
-
if (status === "loading" ||
|
|
1241
|
+
if (status === "loading" || busyRouteRef.current !== null) {
|
|
1242
|
+
patchNotice(draft.provider, {
|
|
1243
|
+
kind: "error",
|
|
1244
|
+
text: t("saveBusy")
|
|
1245
|
+
});
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
945
1248
|
const blocking = draft.models.map((row) => errorText(modelEffortError(row), t)).find((text) => text !== void 0);
|
|
946
1249
|
if (blocking !== void 0) {
|
|
947
1250
|
patchNotice(draft.provider, {
|
|
@@ -950,6 +1253,7 @@ window.__ModuleLoader__.load({
|
|
|
950
1253
|
});
|
|
951
1254
|
return;
|
|
952
1255
|
}
|
|
1256
|
+
busyRouteRef.current = draft.provider;
|
|
953
1257
|
setBusyRoute(draft.provider);
|
|
954
1258
|
patchNotice(draft.provider, void 0);
|
|
955
1259
|
try {
|
|
@@ -961,7 +1265,7 @@ window.__ModuleLoader__.load({
|
|
|
961
1265
|
afterCompat: draft.compat
|
|
962
1266
|
});
|
|
963
1267
|
if (ops.length === 0) {
|
|
964
|
-
|
|
1268
|
+
applyDrafts((current) => current.map((row) => row.provider === draft.provider ? alignDraft(row) : row));
|
|
965
1269
|
return;
|
|
966
1270
|
}
|
|
967
1271
|
const willWriteCompat = ops.some((op) => op.path.length > draft.settingsPath.length && op.path[draft.settingsPath.length] === "compat");
|
|
@@ -995,12 +1299,21 @@ window.__ModuleLoader__.load({
|
|
|
995
1299
|
kind: conflict ? "conflict" : "error",
|
|
996
1300
|
text: conflict ? t("conflict") : response.result.error.message
|
|
997
1301
|
});
|
|
998
|
-
if (conflict)
|
|
1302
|
+
if (conflict) {
|
|
1303
|
+
const { generation, signal } = beginGeneration();
|
|
1304
|
+
waitForNamespaceRevisionChange(describe, LLM_PI_AI_NS, draft.revision, signal).then((outcome) => {
|
|
1305
|
+
if (outcome === "aborted" || !generationIsCurrent(generationRef, generation)) return;
|
|
1306
|
+
return loadSnapshotThenSettle(generation, true);
|
|
1307
|
+
}, (failure) => {
|
|
1308
|
+
failGeneration(generation, failure);
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
999
1311
|
return;
|
|
1000
1312
|
}
|
|
1001
1313
|
const view = response.result.value;
|
|
1314
|
+
echoedRevisionRef.current = view.revision;
|
|
1002
1315
|
describe.acceptView(view);
|
|
1003
|
-
|
|
1316
|
+
applyDrafts(applySaveSuccess(draftsRef.current, draft.provider, {
|
|
1004
1317
|
user: view.user ?? {},
|
|
1005
1318
|
revision: view.revision
|
|
1006
1319
|
}));
|
|
@@ -1014,7 +1327,9 @@ window.__ModuleLoader__.load({
|
|
|
1014
1327
|
text: failure instanceof Error ? failure.message : t("loadError")
|
|
1015
1328
|
});
|
|
1016
1329
|
} finally {
|
|
1330
|
+
busyRouteRef.current = null;
|
|
1017
1331
|
setBusyRoute(null);
|
|
1332
|
+
flushPendingSettings(refreshAtRevision);
|
|
1018
1333
|
}
|
|
1019
1334
|
};
|
|
1020
1335
|
const showLoading = status === "loading" && drafts.length === 0;
|
|
@@ -1049,7 +1364,7 @@ window.__ModuleLoader__.load({
|
|
|
1049
1364
|
type: "button",
|
|
1050
1365
|
className: effort_declare_module_css_default.secondaryButton,
|
|
1051
1366
|
onClick: () => {
|
|
1052
|
-
reload(true);
|
|
1367
|
+
reload(true, snapshotMode());
|
|
1053
1368
|
},
|
|
1054
1369
|
children: t("reload")
|
|
1055
1370
|
}) : null,
|
|
@@ -1067,26 +1382,30 @@ window.__ModuleLoader__.load({
|
|
|
1067
1382
|
formats: formats.length > 0 ? formats : [],
|
|
1068
1383
|
writable,
|
|
1069
1384
|
busy: busyRoute === draft.provider,
|
|
1070
|
-
|
|
1385
|
+
saveLocked: !writable || busyRoute !== null || status === "loading",
|
|
1071
1386
|
notice: notices[draft.provider],
|
|
1072
1387
|
t,
|
|
1073
1388
|
onChange: (next) => {
|
|
1074
1389
|
patchNotice(next.provider, void 0);
|
|
1075
|
-
|
|
1390
|
+
applyDrafts((current) => current.map((row) => row.provider === next.provider ? next : row));
|
|
1076
1391
|
},
|
|
1077
1392
|
onSave: (next) => {
|
|
1078
1393
|
save(next);
|
|
1079
1394
|
},
|
|
1080
1395
|
onCancel: (next) => {
|
|
1081
1396
|
patchNotice(next.provider, void 0);
|
|
1082
|
-
|
|
1397
|
+
applyDrafts((current) => current.map((row) => row.provider === next.provider ? {
|
|
1083
1398
|
...row,
|
|
1084
1399
|
models: cloneModels(row.originalModels),
|
|
1085
1400
|
compat: cloneObject(row.originalCompat)
|
|
1086
1401
|
} : row));
|
|
1087
1402
|
}
|
|
1088
1403
|
}, draft.provider))
|
|
1089
|
-
}) : null
|
|
1404
|
+
}) : null,
|
|
1405
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1406
|
+
className: effort_declare_module_css_default.footer,
|
|
1407
|
+
children: PLUGIN_FOOTER_TEXT
|
|
1408
|
+
})
|
|
1090
1409
|
]
|
|
1091
1410
|
});
|
|
1092
1411
|
}
|
|
@@ -1104,6 +1423,7 @@ window.__ModuleLoader__.load({
|
|
|
1104
1423
|
readOnly: "当前设置为只读,无法保存。",
|
|
1105
1424
|
save: "保存",
|
|
1106
1425
|
saving: "保存中…",
|
|
1426
|
+
saveBusy: "另有路由正在保存,请稍候。",
|
|
1107
1427
|
cancel: "取消",
|
|
1108
1428
|
saved: "已保存。对话选择器会按新的能力声明显示 Effort 行。",
|
|
1109
1429
|
conflict: "设置已被其他地方改过,请重新加载后再保存。",
|
|
@@ -1146,6 +1466,7 @@ window.__ModuleLoader__.load({
|
|
|
1146
1466
|
readOnly: "Settings are read-only; saving is disabled.",
|
|
1147
1467
|
save: "Save",
|
|
1148
1468
|
saving: "Saving…",
|
|
1469
|
+
saveBusy: "Another route is saving. Wait, then save this card.",
|
|
1149
1470
|
cancel: "Cancel",
|
|
1150
1471
|
saved: "Saved. The composer Effort row follows this capability declaration.",
|
|
1151
1472
|
conflict: "Settings changed elsewhere. Reload, then save again.",
|
|
@@ -1222,22 +1543,25 @@ window.__ModuleLoader__.load({
|
|
|
1222
1543
|
const describe = ctx.settingsScope.describe();
|
|
1223
1544
|
const invalidation = /* @__PURE__ */ new Set();
|
|
1224
1545
|
ctx.effect(() => {
|
|
1225
|
-
const emit = (
|
|
1226
|
-
for (const listener of invalidation) listener(
|
|
1546
|
+
const emit = (event) => {
|
|
1547
|
+
for (const listener of invalidation) listener(event);
|
|
1227
1548
|
};
|
|
1228
1549
|
const disposers = [
|
|
1229
1550
|
describe.subscribe(() => {
|
|
1230
|
-
emit("
|
|
1551
|
+
emit({ source: "writable" });
|
|
1231
1552
|
}),
|
|
1232
|
-
ctx.remote.$on("settings/document-updated", (ns) => {
|
|
1553
|
+
ctx.remote.$on("settings/document-updated", (ns, revision) => {
|
|
1233
1554
|
if (ns !== "llm-pi-ai") return;
|
|
1234
|
-
emit(
|
|
1555
|
+
emit({
|
|
1556
|
+
source: "settings",
|
|
1557
|
+
revision
|
|
1558
|
+
});
|
|
1235
1559
|
}),
|
|
1236
1560
|
ctx.remote.$on("llm/adapters-updated", () => {
|
|
1237
|
-
emit("directory");
|
|
1561
|
+
emit({ source: "directory" });
|
|
1238
1562
|
}),
|
|
1239
1563
|
ctx.on("connection/reset", () => {
|
|
1240
|
-
emit("
|
|
1564
|
+
emit({ source: "reset" });
|
|
1241
1565
|
})
|
|
1242
1566
|
];
|
|
1243
1567
|
return () => {
|