@musnows/scriverse 0.7.11 → 0.7.13
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/dist/ai.js +468 -90
- package/dist/ai.js.map +1 -1
- package/dist/app.js +67 -2
- package/dist/app.js.map +1 -1
- package/dist/public/app.js +321 -29
- package/dist/public/index.html +4 -4
- package/dist/public/plain-text-paste.js +89 -0
- package/dist/public/stream-typewriter.d.ts +12 -1
- package/dist/public/stream-typewriter.js +65 -5
- package/dist/public/styles.css +85 -1
- package/dist/store.js +384 -97
- package/dist/store.js.map +1 -1
- package/dist/user-auth.js +1 -1
- package/dist/user-auth.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
function normalizePlainText(value) {
|
|
2
|
+
return String(value ?? "").replace(/\r\n?/gu, "\n");
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function readClipboardPlainText(clipboardData) {
|
|
6
|
+
if (!clipboardData || typeof clipboardData.getData !== "function") return "";
|
|
7
|
+
try {
|
|
8
|
+
return normalizePlainText(clipboardData.getData("text/plain"));
|
|
9
|
+
} catch {
|
|
10
|
+
return "";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isInside(root, node) {
|
|
15
|
+
return Boolean(node) && (node === root || root.contains(node));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function insertIntoContentEditable(target, text, documentRef, windowRef) {
|
|
19
|
+
const selection = windowRef?.getSelection?.();
|
|
20
|
+
const currentRange = selection?.rangeCount ? selection.getRangeAt(0) : null;
|
|
21
|
+
const range = currentRange && isInside(target, currentRange.commonAncestorContainer)
|
|
22
|
+
? currentRange.cloneRange()
|
|
23
|
+
: documentRef.createRange();
|
|
24
|
+
if (!currentRange || !isInside(target, currentRange.commonAncestorContainer)) {
|
|
25
|
+
target.focus?.();
|
|
26
|
+
range.selectNodeContents(target);
|
|
27
|
+
range.collapse(false);
|
|
28
|
+
}
|
|
29
|
+
range.deleteContents();
|
|
30
|
+
const fragment = documentRef.createDocumentFragment();
|
|
31
|
+
normalizePlainText(text).split("\n").forEach((line, index) => {
|
|
32
|
+
if (index > 0) fragment.append(documentRef.createElement("br"));
|
|
33
|
+
if (line) fragment.append(documentRef.createTextNode(line));
|
|
34
|
+
});
|
|
35
|
+
range.insertNode(fragment);
|
|
36
|
+
range.collapse(false);
|
|
37
|
+
if (selection) {
|
|
38
|
+
selection.removeAllRanges();
|
|
39
|
+
selection.addRange(range);
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function insertIntoTextArea(target, text) {
|
|
45
|
+
const value = String(target.value ?? "");
|
|
46
|
+
const start = Number.isInteger(target.selectionStart) ? target.selectionStart : value.length;
|
|
47
|
+
const end = Number.isInteger(target.selectionEnd) ? target.selectionEnd : start;
|
|
48
|
+
target.value = `${value.slice(0, start)}${normalizePlainText(text)}${value.slice(end)}`;
|
|
49
|
+
target.setSelectionRange?.(start + normalizePlainText(text).length, start + normalizePlainText(text).length);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function dispatchInput(target, text, windowRef) {
|
|
54
|
+
const InputEventConstructor = windowRef?.InputEvent;
|
|
55
|
+
const EventConstructor = windowRef?.Event;
|
|
56
|
+
if (typeof InputEventConstructor === "function") {
|
|
57
|
+
target.dispatchEvent(new InputEventConstructor("input", { bubbles: true, inputType: "insertFromPaste", data: text }));
|
|
58
|
+
} else if (typeof EventConstructor === "function") {
|
|
59
|
+
target.dispatchEvent(new EventConstructor("input", { bubbles: true }));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function insertClipboardPlainText(target, text, documentRef = globalThis.document, windowRef = globalThis.window) {
|
|
64
|
+
if (!target) return false;
|
|
65
|
+
if (target.tagName === "TEXTAREA") return insertIntoTextArea(target, text);
|
|
66
|
+
if (target.getAttribute?.("contenteditable") === "true") return insertIntoContentEditable(target, text, documentRef, windowRef);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function pasteTarget(event, root) {
|
|
71
|
+
let target = event.target;
|
|
72
|
+
if (target?.nodeType !== 1) target = target?.parentElement;
|
|
73
|
+
const editable = target?.closest?.("textarea, [contenteditable=\"true\"]");
|
|
74
|
+
return editable && isInside(root, editable) ? editable : null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function bindPlainTextPaste(root, documentRef = globalThis.document, windowRef = globalThis.window) {
|
|
78
|
+
if (!root) return () => {};
|
|
79
|
+
const handler = (event) => {
|
|
80
|
+
const target = pasteTarget(event, root);
|
|
81
|
+
if (!target) return;
|
|
82
|
+
const text = readClipboardPlainText(event.clipboardData);
|
|
83
|
+
event.preventDefault();
|
|
84
|
+
event.stopImmediatePropagation();
|
|
85
|
+
if (insertClipboardPlainText(target, text, documentRef, windowRef)) dispatchInput(target, text, windowRef);
|
|
86
|
+
};
|
|
87
|
+
root.addEventListener("paste", handler, true);
|
|
88
|
+
return () => root.removeEventListener("paste", handler, true);
|
|
89
|
+
}
|
|
@@ -9,11 +9,22 @@ export type StreamTypewriter = {
|
|
|
9
9
|
reveal(): string;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
export
|
|
12
|
+
export type StreamTypewriterSpeedController = {
|
|
13
|
+
observe(characterCount: number): void;
|
|
14
|
+
charactersPerSecond(): number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function createStreamTypewriterSpeedController(options?: {
|
|
18
|
+
now?: () => number;
|
|
19
|
+
initialCharactersPerSecond?: number;
|
|
20
|
+
}): StreamTypewriterSpeedController;
|
|
21
|
+
|
|
22
|
+
export function streamTypewriterBatchSize(pendingCharacters: number, finishing?: boolean, charactersPerSecond?: number): number;
|
|
13
23
|
|
|
14
24
|
export function createStreamTypewriter<FrameHandle = number>(options: {
|
|
15
25
|
onRender: (text: string, progress: StreamTypewriterProgress) => void;
|
|
16
26
|
scheduleFrame?: (callback: () => void) => FrameHandle;
|
|
17
27
|
cancelFrame?: (handle: FrameHandle) => void;
|
|
18
28
|
reducedMotion?: boolean;
|
|
29
|
+
speedController?: StreamTypewriterSpeedController | null;
|
|
19
30
|
}): StreamTypewriter;
|
|
@@ -3,15 +3,69 @@ const FINISHING_CHARACTERS_PER_FRAME = 2;
|
|
|
3
3
|
const FINISHING_ACCELERATION = 0.9;
|
|
4
4
|
const MAX_STREAMING_CHARACTERS_PER_FRAME = 12;
|
|
5
5
|
const MAX_FINISHING_CHARACTERS_PER_FRAME = 24;
|
|
6
|
+
const STREAMING_FRAME_RATE = 60;
|
|
7
|
+
const DEFAULT_STREAMING_CHARACTERS_PER_SECOND = STREAMING_CHARACTERS_PER_FRAME * STREAMING_FRAME_RATE;
|
|
8
|
+
const MIN_STREAMING_CHARACTERS_PER_SECOND = DEFAULT_STREAMING_CHARACTERS_PER_SECOND;
|
|
9
|
+
const MAX_STREAMING_CHARACTERS_PER_SECOND = MAX_STREAMING_CHARACTERS_PER_FRAME * STREAMING_FRAME_RATE;
|
|
10
|
+
const SPEED_SAMPLE_MAX_GAP_MS = 1_000;
|
|
11
|
+
const SPEED_SMOOTHING = 0.25;
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
function clampCharactersPerSecond(value) {
|
|
14
|
+
const speed = Number(value);
|
|
15
|
+
if (!Number.isFinite(speed)) return DEFAULT_STREAMING_CHARACTERS_PER_SECOND;
|
|
16
|
+
return Math.min(MAX_STREAMING_CHARACTERS_PER_SECOND, Math.max(MIN_STREAMING_CHARACTERS_PER_SECOND, speed));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function currentTime() {
|
|
20
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function createStreamTypewriterSpeedController({
|
|
24
|
+
now = currentTime,
|
|
25
|
+
initialCharactersPerSecond = DEFAULT_STREAMING_CHARACTERS_PER_SECOND
|
|
26
|
+
} = {}) {
|
|
27
|
+
let charactersPerSecond = clampCharactersPerSecond(initialCharactersPerSecond);
|
|
28
|
+
let lastObservedAt = null;
|
|
29
|
+
|
|
30
|
+
const update = (observedCharactersPerSecond) => {
|
|
31
|
+
const observed = clampCharactersPerSecond(observedCharactersPerSecond);
|
|
32
|
+
charactersPerSecond = clampCharactersPerSecond(
|
|
33
|
+
charactersPerSecond + (observed - charactersPerSecond) * SPEED_SMOOTHING
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
observe(characterCount) {
|
|
39
|
+
const characters = Math.max(0, Math.floor(Number(characterCount) || 0));
|
|
40
|
+
if (characters === 0) return;
|
|
41
|
+
const observedAt = Number(now());
|
|
42
|
+
if (Number.isFinite(observedAt) && lastObservedAt !== null) {
|
|
43
|
+
const elapsed = observedAt - lastObservedAt;
|
|
44
|
+
if (elapsed > 0 && elapsed <= SPEED_SAMPLE_MAX_GAP_MS) {
|
|
45
|
+
update(characters / elapsed * 1_000);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (Number.isFinite(observedAt)) lastObservedAt = observedAt;
|
|
49
|
+
|
|
50
|
+
// 单次收到的大块内容也需要让同一条流的后续轮次继承当前的追赶速度。
|
|
51
|
+
const backlogSpeed = Math.ceil(characters / 30) * STREAMING_FRAME_RATE;
|
|
52
|
+
if (backlogSpeed > charactersPerSecond) charactersPerSecond = Math.min(MAX_STREAMING_CHARACTERS_PER_SECOND, backlogSpeed);
|
|
53
|
+
},
|
|
54
|
+
charactersPerSecond() {
|
|
55
|
+
return charactersPerSecond;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function streamTypewriterBatchSize(pendingCharacters, finishing = false, charactersPerSecond = DEFAULT_STREAMING_CHARACTERS_PER_SECOND) {
|
|
8
61
|
const pending = Math.max(0, Math.floor(Number(pendingCharacters) || 0));
|
|
9
62
|
if (pending === 0) return 0;
|
|
10
63
|
const minimum = finishing ? FINISHING_CHARACTERS_PER_FRAME : STREAMING_CHARACTERS_PER_FRAME;
|
|
11
64
|
const maximum = finishing ? MAX_FINISHING_CHARACTERS_PER_FRAME : MAX_STREAMING_CHARACTERS_PER_FRAME;
|
|
65
|
+
const speedBased = Math.ceil(clampCharactersPerSecond(charactersPerSecond) / STREAMING_FRAME_RATE);
|
|
12
66
|
const adaptive = finishing
|
|
13
|
-
? Math.ceil(Math.sqrt(pending) * FINISHING_ACCELERATION)
|
|
14
|
-
: Math.ceil(pending / 30);
|
|
67
|
+
? Math.max(Math.ceil(Math.sqrt(pending) * FINISHING_ACCELERATION), speedBased)
|
|
68
|
+
: Math.max(Math.ceil(pending / 30), speedBased);
|
|
15
69
|
return Math.min(pending, maximum, Math.max(minimum, adaptive));
|
|
16
70
|
}
|
|
17
71
|
|
|
@@ -19,7 +73,8 @@ export function createStreamTypewriter({
|
|
|
19
73
|
onRender,
|
|
20
74
|
scheduleFrame = (callback) => window.requestAnimationFrame(callback),
|
|
21
75
|
cancelFrame = (handle) => window.cancelAnimationFrame(handle),
|
|
22
|
-
reducedMotion = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches === true
|
|
76
|
+
reducedMotion = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches === true,
|
|
77
|
+
speedController = null
|
|
23
78
|
}) {
|
|
24
79
|
if (typeof onRender !== "function") throw new TypeError("onRender must be a function");
|
|
25
80
|
|
|
@@ -47,7 +102,11 @@ export function createStreamTypewriter({
|
|
|
47
102
|
scheduledFrame = null;
|
|
48
103
|
const batchSize = reducedMotion
|
|
49
104
|
? pendingCharacters.length
|
|
50
|
-
: streamTypewriterBatchSize(
|
|
105
|
+
: streamTypewriterBatchSize(
|
|
106
|
+
pendingCharacters.length,
|
|
107
|
+
finishing,
|
|
108
|
+
speedController?.charactersPerSecond?.()
|
|
109
|
+
);
|
|
51
110
|
visibleCharacters.push(...pendingCharacters.splice(0, batchSize));
|
|
52
111
|
render();
|
|
53
112
|
if (pendingCharacters.length) schedule();
|
|
@@ -59,6 +118,7 @@ export function createStreamTypewriter({
|
|
|
59
118
|
append(value) {
|
|
60
119
|
const characters = Array.from(String(value ?? ""));
|
|
61
120
|
if (!characters.length) return;
|
|
121
|
+
speedController?.observe?.(characters.length);
|
|
62
122
|
pendingCharacters.push(...characters);
|
|
63
123
|
schedule();
|
|
64
124
|
},
|
package/dist/public/styles.css
CHANGED
|
@@ -1788,6 +1788,8 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
|
|
|
1788
1788
|
.character-extraction-editor-toolbar { justify-content: flex-end; }
|
|
1789
1789
|
.character-extraction-editor-toolbar > span { margin-right: auto; color: var(--accent-dark); font-weight: 600; }
|
|
1790
1790
|
.character-extraction-editor-toolbar button { padding: 6px 9px; font-size: 9px; }
|
|
1791
|
+
.character-extraction-apply-button { flex: 0 0 auto; }
|
|
1792
|
+
.character-extraction-apply-note { margin: -5px 0 0; color: var(--muted); font-size: 9px; line-height: 1.5; }
|
|
1791
1793
|
.character-extraction-candidate-list { display: grid; gap: 9px; min-width: 0; }
|
|
1792
1794
|
.character-extraction-candidate { display: grid; gap: 10px; min-width: 0; padding: 11px; border: 1px solid var(--line); border-radius: 6px; background: var(--surface-soft); transition: opacity .15s ease, border-color .15s ease; }
|
|
1793
1795
|
.character-extraction-candidate.is-skipped { opacity: .7; }
|
|
@@ -2582,7 +2584,11 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
|
|
|
2582
2584
|
.ai-tool-call-info code, .ai-tool-call-info time { font-family: var(--font-latin), monospace; }
|
|
2583
2585
|
.ai-tool-call-detail section { min-width: 0; }
|
|
2584
2586
|
.ai-tool-call-detail h3 { margin: 0 0 7px; color: var(--muted); font-size: 10px; font-weight: 600; }
|
|
2585
|
-
.ai-tool-call-
|
|
2587
|
+
.ai-tool-call-code-block { position: relative; min-width: 0; }
|
|
2588
|
+
.ai-tool-call-detail pre { min-height: 120px; max-height: 32vh; overflow: auto; margin: 0; padding: 30px 12px 12px; border: 1px solid var(--line); border-radius: 5px; background: var(--paper-deep); color: var(--ink); font: 10px/1.55 var(--font-latin), monospace; white-space: pre-wrap; word-break: break-word; }
|
|
2589
|
+
.ai-tool-call-copy-button { position: absolute; z-index: 1; top: 6px; right: 6px; display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; min-height: 0; padding: 0; border: 1px solid transparent; border-radius: 4px; background: color-mix(in srgb, var(--paper-deep) 86%, var(--ink)); color: var(--muted); }
|
|
2590
|
+
.ai-tool-call-copy-button svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.7; }
|
|
2591
|
+
.ai-tool-call-copy-button:hover, .ai-tool-call-copy-button:focus-visible, .ai-tool-call-copy-button.is-copied { border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); background: color-mix(in srgb, var(--accent) 12%, var(--paper-deep)); color: var(--accent-dark); outline: none; }
|
|
2586
2592
|
#ai-tool-call-arguments { min-height: 0; max-height: 26vh; }
|
|
2587
2593
|
.ai-tool-call-detail section:last-child pre { min-height: 180px; }
|
|
2588
2594
|
@media (max-width: 680px) { .ai-tool-call-info { grid-template-columns: minmax(0, 1fr); }.ai-tool-call-detail pre { min-height: 100px; max-height: 26vh; }#ai-tool-call-arguments { min-height: 0; max-height: 20vh; }.ai-tool-call-detail section:last-child pre { min-height: 140px; } }
|
|
@@ -2701,6 +2707,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
|
|
|
2701
2707
|
line-height: 1.55;
|
|
2702
2708
|
animation: toast-appear-top .18s ease;
|
|
2703
2709
|
}
|
|
2710
|
+
.toast.ai-new-conversation-toast { white-space: pre-line; }
|
|
2704
2711
|
.toast-region[data-position="bottom-right"] .toast { animation-name: toast-appear-bottom; }
|
|
2705
2712
|
.toast.error {
|
|
2706
2713
|
border-color: color-mix(in srgb, var(--toast-error-fg) 16%, transparent);
|
|
@@ -2835,6 +2842,10 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
|
|
|
2835
2842
|
.dialog-fields .form-field-note { margin: 0; color: var(--muted); font-size: 11px; line-height: 1.65; }
|
|
2836
2843
|
.dialog-fields label { display: grid; gap: 6px; color: var(--muted); font-size: 11px; }
|
|
2837
2844
|
.dialog-fields input, .dialog-fields textarea, .dialog-fields select { width: 100%; padding: 9px 10px; font-size: 13px; }
|
|
2845
|
+
.dialog-fields select { padding-inline-end: 28px; }
|
|
2846
|
+
.dialog-fields .character-extraction-candidate-toggle { display: inline-flex; width: auto; align-items: center; gap: 7px; margin: 0; color: var(--ink); font-size: 9px; white-space: nowrap; }
|
|
2847
|
+
.dialog-fields .character-extraction-candidate-toggle input[type="checkbox"] { flex: 0 0 18px; width: 18px; min-width: 18px; height: 18px; padding: 0; }
|
|
2848
|
+
.dialog-fields .character-extraction-candidate-toggle input[type="checkbox"]:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent); }
|
|
2838
2849
|
.dialog-fields textarea { resize: vertical; min-height: 90px; line-height: 1.6; }
|
|
2839
2850
|
.system-restart-dialog { width: min(500px, 92vw); }
|
|
2840
2851
|
.system-restart-message { margin: 0; color: var(--ink); font-size: 13px; line-height: 1.7; }
|
|
@@ -2878,6 +2889,75 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
|
|
|
2878
2889
|
.task-chapter-field { transition: opacity .15s ease; }
|
|
2879
2890
|
.task-chapter-field.is-disabled { opacity: .48; }
|
|
2880
2891
|
.task-chapter-field select:disabled { cursor: not-allowed; }
|
|
2892
|
+
.task-scope-field { min-width: 0; transition: opacity .15s ease; }
|
|
2893
|
+
.task-scope-field.is-disabled { opacity: .48; }
|
|
2894
|
+
.task-scope-field-heading { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; min-width: 0; color: var(--muted); font-size: 11px; }
|
|
2895
|
+
.task-scope-field-heading > span { min-width: 0; }
|
|
2896
|
+
.task-scope-field-heading small { color: var(--muted); font-size: 9px; }
|
|
2897
|
+
.task-scope-picker { display: grid; gap: 8px; min-width: 0; }
|
|
2898
|
+
.dialog-fields .task-scope-trigger { display: flex; width: 100%; min-height: 42px; align-items: center; justify-content: space-between; gap: 12px; padding: 9px 11px; border: 1px solid var(--line); border-radius: 4px; background: var(--surface); color: var(--ink); font-size: 12px; line-height: 1.2; text-align: left; }
|
|
2899
|
+
.task-scope-trigger:hover, .task-scope-trigger:focus-visible, .task-scope-trigger[aria-expanded="true"] { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 12%, transparent); outline: none; }
|
|
2900
|
+
.task-scope-trigger:disabled { cursor: not-allowed; opacity: .48; }
|
|
2901
|
+
.task-scope-trigger > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2902
|
+
.task-scope-trigger-meta { display: inline-flex; flex: 0 0 auto; height: 18px; align-items: center; gap: 8px; color: var(--muted); font-family: var(--font-latin), monospace; font-size: 10px; line-height: 1; }
|
|
2903
|
+
.task-scope-chevron { display: inline-grid; width: 16px; height: 18px; place-items: center; font-size: 15px; line-height: 1; transition: transform .15s ease; }
|
|
2904
|
+
.task-scope-trigger[aria-expanded="true"] .task-scope-chevron { transform: rotate(180deg); }
|
|
2905
|
+
.task-scope-panel { display: grid; gap: 14px; min-width: 0; padding: 14px; border: 1px solid color-mix(in srgb, var(--accent) 36%, var(--line)); border-radius: 8px; background: var(--surface-soft); box-shadow: 0 12px 30px rgba(48,39,31,.12); }
|
|
2906
|
+
.task-scope-panel.hidden { display: none; }
|
|
2907
|
+
.task-scope-panel-header, .task-scope-panel-section-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-width: 0; }
|
|
2908
|
+
.task-scope-panel-header > div, .task-scope-panel-section-header > div { display: grid; gap: 3px; min-width: 0; }
|
|
2909
|
+
.task-scope-panel-header strong, .task-scope-panel-section-header strong { color: var(--ink); font-size: 11px; font-weight: 650; }
|
|
2910
|
+
.task-scope-panel-header small { color: var(--muted); font-size: 9px; line-height: 1.5; }
|
|
2911
|
+
.task-scope-author-note-banner { display: grid; grid-template-columns: 20px minmax(0, 1fr); align-items: start; gap: 8px; padding: 9px 10px; border: 1px solid color-mix(in srgb, var(--accent) 34%, var(--line)); border-left: 3px solid var(--accent); border-radius: 6px; background: color-mix(in srgb, var(--accent) 8%, var(--surface)); color: var(--muted); font-size: 9px; line-height: 1.55; }
|
|
2912
|
+
.task-scope-author-note-banner-icon { display: grid; width: 18px; height: 18px; place-items: center; border-radius: 50%; background: var(--accent); color: #fff; font-family: var(--font-latin), monospace; font-size: 11px; font-weight: 700; line-height: 1; }
|
|
2913
|
+
.task-scope-author-note-banner div { display: grid; gap: 2px; min-width: 0; }
|
|
2914
|
+
.task-scope-author-note-banner strong { color: var(--accent-dark); font-size: 10px; }
|
|
2915
|
+
.task-scope-clear { flex: 0 0 auto; padding: 5px 7px; border: 1px solid var(--line); border-radius: 4px; background: transparent; color: var(--accent-dark); font-size: 9px; }
|
|
2916
|
+
.task-scope-clear:hover:not(:disabled), .task-scope-clear:focus-visible { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 7%, transparent); outline: none; }
|
|
2917
|
+
.task-scope-clear:disabled { cursor: default; opacity: .45; }
|
|
2918
|
+
.task-scope-panel-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(230px, .8fr); gap: 12px; min-width: 0; }
|
|
2919
|
+
.task-scope-available, .task-scope-selected { display: grid; align-content: start; gap: 10px; min-width: 0; min-height: 360px; padding: 12px; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); }
|
|
2920
|
+
.task-scope-panel-section-header > span { flex: 0 0 auto; color: var(--muted); font-family: var(--font-latin), monospace; font-size: 9px; }
|
|
2921
|
+
.task-scope-search { gap: 5px !important; }
|
|
2922
|
+
.task-scope-search > span { color: var(--muted); font-size: 9px; }
|
|
2923
|
+
.dialog-fields .task-scope-search input { min-height: 34px; padding: 6px 9px; background: var(--surface-soft); font-size: 10px; }
|
|
2924
|
+
.task-scope-options { display: grid; align-content: start; gap: 6px; max-height: min(42vh, 360px); overflow-y: auto; padding: 2px 4px 2px 0; }
|
|
2925
|
+
.task-scope-volume-group { display: grid; gap: 5px; min-width: 0; padding: 5px 0 7px; border-bottom: 1px solid color-mix(in srgb, var(--line) 72%, transparent); }
|
|
2926
|
+
.task-scope-volume-group:last-child { border-bottom: 0; }
|
|
2927
|
+
.task-scope-volume-group > header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 0 2px 2px; }
|
|
2928
|
+
.task-scope-volume-group > header strong { overflow: hidden; color: var(--accent-dark); font-size: 10px; text-overflow: ellipsis; white-space: nowrap; }
|
|
2929
|
+
.task-scope-volume-group > header span { flex: 0 0 auto; color: var(--muted); font-family: var(--font-latin), monospace; font-size: 8px; }
|
|
2930
|
+
.dialog-fields .task-scope-volume-option { position: relative; display: grid; grid-template-columns: 18px minmax(0, 1fr); align-items: center; gap: 8px; min-width: 0; margin: 0; color: var(--ink); cursor: pointer; }
|
|
2931
|
+
.task-scope-volume-option input { position: absolute; width: 1px !important; min-width: 1px; height: 1px; padding: 0; border: 0; opacity: 0; }
|
|
2932
|
+
.task-scope-volume-option:hover, .task-scope-volume-option:has(input:focus-visible) { color: var(--accent-dark); }
|
|
2933
|
+
.task-scope-volume-option:has(input:checked) .task-scope-checkbox, .task-scope-volume-option:has(input:indeterminate) .task-scope-checkbox { border-color: var(--accent); background: var(--accent); }
|
|
2934
|
+
.task-scope-volume-option:has(input:checked) .task-scope-checkbox::after { opacity: 1; transform: translateY(-1px) rotate(-45deg) scale(1); }
|
|
2935
|
+
.task-scope-volume-option input:indeterminate + .task-scope-checkbox::after { width: 8px; height: 2px; border: 0; background: #fff; opacity: 1; transform: none; }
|
|
2936
|
+
.task-scope-volume-copy { display: grid; gap: 2px; min-width: 0; }
|
|
2937
|
+
.task-scope-volume-copy strong { overflow: hidden; color: inherit !important; font-size: 10px; text-overflow: ellipsis; white-space: nowrap; }
|
|
2938
|
+
.task-scope-volume-copy small { overflow: hidden; color: var(--muted); font-size: 8px; text-overflow: ellipsis; white-space: nowrap; }
|
|
2939
|
+
.dialog-fields .task-scope-option { position: relative; display: grid; grid-template-columns: 18px minmax(0, 1fr); align-items: center; gap: 8px; min-width: 0; padding: 8px 9px; border: 1px solid var(--line); border-radius: 5px; background: var(--surface-soft); color: var(--muted); cursor: pointer; transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease; }
|
|
2940
|
+
.dialog-fields .task-scope-option.hidden { display: none; }
|
|
2941
|
+
.task-scope-option:hover, .task-scope-option:has(input:focus-visible) { border-color: color-mix(in srgb, var(--accent) 54%, var(--line)); }
|
|
2942
|
+
.task-scope-option input { position: absolute; width: 1px !important; min-width: 1px; height: 1px; padding: 0; border: 0; opacity: 0; }
|
|
2943
|
+
.task-scope-checkbox { display: inline-grid; width: 18px; height: 18px; place-items: center; border: 1px solid var(--line-strong); border-radius: 4px; background: var(--surface); transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease; }
|
|
2944
|
+
.task-scope-checkbox::after { width: 8px; height: 5px; border: solid #fff; border-width: 0 0 2px 2px; content: ""; opacity: 0; transform: translateY(-1px) rotate(-45deg) scale(.7); transition: opacity .12s ease, transform .12s ease; }
|
|
2945
|
+
.task-scope-option strong { overflow: hidden; color: var(--ink); font-size: 10px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
|
|
2946
|
+
.task-scope-option-copy { display: grid; gap: 2px; min-width: 0; }
|
|
2947
|
+
.task-scope-option small { overflow: hidden; color: var(--muted); font-size: 9px; text-overflow: ellipsis; white-space: nowrap; }
|
|
2948
|
+
.task-scope-option:has(input:checked) { border-color: color-mix(in srgb, var(--accent) 62%, var(--line)); background: color-mix(in srgb, var(--accent) 7%, var(--surface)); box-shadow: inset 2px 0 var(--accent); }
|
|
2949
|
+
.task-scope-option:has(input:checked) .task-scope-checkbox { border-color: var(--accent); background: var(--accent); }
|
|
2950
|
+
.task-scope-option:has(input:checked) .task-scope-checkbox::after { opacity: 1; transform: translateY(-1px) rotate(-45deg) scale(1); }
|
|
2951
|
+
.task-scope-selected-note { margin: -2px 0 0; color: var(--muted); font-size: 9px; line-height: 1.5; }
|
|
2952
|
+
.task-scope-selected-list { display: grid; align-content: start; gap: 6px; max-height: min(42vh, 360px); overflow-y: auto; padding: 2px 4px 2px 0; }
|
|
2953
|
+
.task-scope-selected-item { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 8px; min-width: 0; padding: 8px 9px; border: 1px solid color-mix(in srgb, var(--accent) 32%, var(--line)); border-radius: 5px; background: color-mix(in srgb, var(--accent) 5%, var(--surface)); }
|
|
2954
|
+
.task-scope-selected-copy { display: grid; gap: 2px; min-width: 0; }
|
|
2955
|
+
.task-scope-selected-copy strong { overflow: hidden; color: var(--ink); font-size: 10px; text-overflow: ellipsis; white-space: nowrap; }
|
|
2956
|
+
.task-scope-selected-copy small { overflow: hidden; color: var(--muted); font-size: 9px; text-overflow: ellipsis; white-space: nowrap; }
|
|
2957
|
+
.task-scope-selected-item button { display: grid; width: 24px; height: 24px; place-items: center; padding: 0; border: 1px solid transparent; border-radius: 50%; background: transparent; color: var(--muted); font-size: 16px; line-height: 1; }
|
|
2958
|
+
.task-scope-selected-item button:hover, .task-scope-selected-item button:focus-visible { border-color: var(--line); background: var(--surface); color: var(--accent-dark); outline: none; }
|
|
2959
|
+
.task-scope-selected-empty { margin: 0; padding: 28px 12px; border: 1px dashed var(--line); color: var(--muted); font-size: 10px; line-height: 1.5; text-align: center; }
|
|
2960
|
+
.task-scope-empty { margin: 0; padding: 18px 8px; color: var(--muted); font-size: 10px; text-align: center; }
|
|
2881
2961
|
.relationship-analysis-options { display: grid; gap: 14px; }
|
|
2882
2962
|
.relationship-character-field { min-width: 0; }
|
|
2883
2963
|
.relationship-character-picker { display: grid; gap: 8px; min-width: 0; }
|
|
@@ -2927,6 +3007,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
|
|
|
2927
3007
|
.relationship-source-preview-match { padding: 2px 6px; border-radius: 10px; background: color-mix(in srgb, var(--accent) 10%, transparent); color: var(--accent-dark); font-size: 8px; white-space: nowrap; }
|
|
2928
3008
|
.relationship-source-preview-match.is-fuzzy { background: color-mix(in srgb, var(--warning, #a56f19) 12%, transparent); color: var(--warning, #8b5c10); }
|
|
2929
3009
|
.relationship-source-preview-empty { margin: 0; padding: 9px; border: 1px dashed var(--line); border-radius: 4px; }
|
|
3010
|
+
.analysis-context-warning { margin: 7px 0 0; padding: 8px 10px; border: 1px solid color-mix(in srgb, var(--warning, #a56f19) 45%, var(--line)); border-radius: 4px; background: color-mix(in srgb, var(--warning, #a56f19) 9%, transparent); color: var(--warning, #8b5c10); font-size: 10px; line-height: 1.55; }
|
|
2930
3011
|
.model-temperature-hint, .model-context-window-hint { margin: 0; color: var(--accent-dark); font-size: 10px; line-height: 1.55; }
|
|
2931
3012
|
.item-list-rows { display: grid; gap: 7px; }
|
|
2932
3013
|
.item-list-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 7px; }
|
|
@@ -3655,6 +3736,9 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
|
|
|
3655
3736
|
.replace-scope-fieldset legend, .replace-scope-fieldset > p { grid-column: auto; }
|
|
3656
3737
|
.task-detail-overview { grid-template-columns: minmax(0, 1fr); padding: 12px; }
|
|
3657
3738
|
.task-detail-overview > * { grid-column: 1 !important; }
|
|
3739
|
+
.task-scope-panel-grid { grid-template-columns: minmax(0, 1fr); }
|
|
3740
|
+
.task-scope-available, .task-scope-selected { min-height: 0; }
|
|
3741
|
+
.task-scope-options, .task-scope-selected-list { max-height: 28vh; }
|
|
3658
3742
|
.task-result-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
3659
3743
|
.task-result-item-details, .task-result-json-loader { grid-template-columns: minmax(0, 1fr); }
|
|
3660
3744
|
.task-result-json-loader button { justify-self: start; }
|