@musnows/scriverse 0.6.4 → 0.6.6
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 +22 -15
- package/dist/ai.js.map +1 -1
- package/dist/app.js +4 -0
- package/dist/app.js.map +1 -1
- package/dist/cli-contract.js +6 -5
- package/dist/cli-contract.js.map +1 -1
- package/dist/database.js +45 -1
- package/dist/database.js.map +1 -1
- package/dist/public/ai-mentions.js +5 -1
- package/dist/public/app.js +102 -52
- package/dist/public/character-version.js +1 -0
- package/dist/public/index.html +6 -10
- package/dist/public/styles.css +82 -49
- package/dist/public/timeline-view.d.ts +50 -0
- package/dist/public/timeline-view.js +119 -0
- package/dist/store.js +40 -25
- package/dist/store.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/public/app.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { buildRelationshipGraph, createGalaxyRenderer, renderRelationshipMindMap } from "/relationship-graph.js?v=20260728-galaxy-edge-stars-v3";
|
|
2
2
|
import { collapseExcessBlankLines, formatDateTime, normalizeParagraphSpacing } from "/text-formatting.js?v=20260713-saved-at-seconds";
|
|
3
3
|
import { renderMarkdown } from "/markdown.js?v=20260731-no-external-images-v1";
|
|
4
|
-
import { findAiMention, listAiMentionOptions, mergeAiReferenceScope } from "/ai-mentions.js?v=20260801-context-
|
|
4
|
+
import { findAiMention, listAiMentionOptions, mergeAiReferenceScope } from "/ai-mentions.js?v=20260801-context-setting-mention-v1";
|
|
5
5
|
import { shouldShowAiQuickActions } from "/ai-conversation.js?v=20260713-quick-actions";
|
|
6
6
|
import { calculateLineNumberRowHeight, calculateLineNumberRowTop, calculateLineNumberTextOffset, calculateLineNumberTop } from "/line-number-layout.js?v=20260713-row-box-alignment";
|
|
7
7
|
import { buildVditorLineNumberRows } from "/vditor-line-number-layout.js?v=20260729-vditor-line-numbers-v3";
|
|
@@ -16,7 +16,7 @@ import { formatAiToolCallResult } from "/ai-tool-call.js?v=20260801-ai-tool-resu
|
|
|
16
16
|
import { copyAiRawMarkdown } from "/ai-message-actions.js?v=20260713-copy-raw-markdown";
|
|
17
17
|
import { THEME_STORAGE_KEY, nextTheme, normalizeTheme, themeToggleLabel } from "/theme.js?v=20260713-dark-mode";
|
|
18
18
|
import { buildCharacterDetails, buildCharacterState, characterStateEntries, normalizeCharacterDetails, normalizeCharacterSections } from "/character-profile.js?v=20260713-character-editor";
|
|
19
|
-
import { characterVersionSourceLabel, describeCharacterVersionChanges } from "/character-version.js?v=
|
|
19
|
+
import { characterVersionSourceLabel, describeCharacterVersionChanges } from "/character-version.js?v=20260801-entity-lifecycle-v1";
|
|
20
20
|
import { VERSIONED_ENTITY_LABELS, entityVersionSnapshotSummary, entityVersionSourceLabel } from "/entity-version.js?v=20260731-drafts-to-ideas-v1";
|
|
21
21
|
import {
|
|
22
22
|
chapterVersionSourceLabel,
|
|
@@ -48,6 +48,12 @@ import { isGlobalSearchShortcut } from "/keyboard-shortcuts.js?v=20260723-global
|
|
|
48
48
|
import { resolveGlobalSearchTarget, splitGlobalSearchHighlight } from "/global-search.js?v=20260728-hybrid-search-v1";
|
|
49
49
|
import { filterCharacters, paginateCharacters } from "/character-filters.js?v=20260725-character-filters";
|
|
50
50
|
import { filterRelationships } from "/relationship-filters.js?v=20260726-relationship-filters";
|
|
51
|
+
import {
|
|
52
|
+
prepareTimelineEvents,
|
|
53
|
+
resolveTimelineActiveTrackId,
|
|
54
|
+
normalizeTimelineSortDirection,
|
|
55
|
+
timelineTrackColorIndex
|
|
56
|
+
} from "/timeline-view.js?v=20260801-timeline-sort-actions-v1";
|
|
51
57
|
import { backgroundTaskActivityCount, backgroundTaskPollDelay, collectBackgroundTaskTransitions } from "/background-task-center.js?v=20260726-background-task-center-v1";
|
|
52
58
|
import { createModuleRequestCache } from "/module-request-cache.js?v=20260730-module-request-cache-v1";
|
|
53
59
|
import { systemStatusPresentation } from "/system-status.js?v=20260801-system-health-v1";
|
|
@@ -177,6 +183,8 @@ const chapterBatchSelectedIds = new Set();
|
|
|
177
183
|
let chapterMovePending = false;
|
|
178
184
|
|
|
179
185
|
let timelineMultiSelectEnabled = false;
|
|
186
|
+
let timelineActiveTrackId = null;
|
|
187
|
+
let timelineSortDirection = "asc";
|
|
180
188
|
let taskProgressRefreshTimer = null;
|
|
181
189
|
let taskAutoRunEditing = false;
|
|
182
190
|
let taskAutoRunEditingWorkId = null;
|
|
@@ -1285,7 +1293,7 @@ function aiReferenceKey(reference) {
|
|
|
1285
1293
|
}
|
|
1286
1294
|
|
|
1287
1295
|
function aiReferenceKindLabel(reference) {
|
|
1288
|
-
return ({ character: "角色", setting: "设定", chapter: "章节" })[reference.kind] ?? "引用";
|
|
1296
|
+
return ({ character: "角色", setting: "设定", chapter: "章节", "context-settings": "能力" })[reference.kind] ?? "引用";
|
|
1289
1297
|
}
|
|
1290
1298
|
|
|
1291
1299
|
function createAiReferenceChip(reference) {
|
|
@@ -1872,15 +1880,12 @@ function syncAiTaskOptions() {
|
|
|
1872
1880
|
$("#ai-scope").setAttribute("aria-hidden", String(roleplaySelected));
|
|
1873
1881
|
$("#ai-roleplay-character").classList.toggle("hidden", !roleplaySelected);
|
|
1874
1882
|
$("#ai-roleplay-character").setAttribute("aria-hidden", String(!roleplaySelected));
|
|
1875
|
-
$(".ai-include-setting-info").classList.toggle("hidden", roleplaySelected);
|
|
1876
|
-
$(".ai-include-setting-info").setAttribute("aria-hidden", String(roleplaySelected));
|
|
1877
1883
|
$("#ai-task").disabled = state.aiPromptSent;
|
|
1878
1884
|
$("#ai-task").title = state.aiPromptSent ? "对话开始后不能切换任务类型" : "";
|
|
1879
1885
|
$("#ai-scope").disabled = roleplaySelected || state.aiPromptSent;
|
|
1880
1886
|
$("#ai-scope").title = state.aiPromptSent
|
|
1881
1887
|
? "对话开始后不能切换上下文引用"
|
|
1882
1888
|
: roleplaySelected ? "角色扮演模式只使用角色自身的记忆" : "";
|
|
1883
|
-
syncAiIncludeSettingInfoControl();
|
|
1884
1889
|
}
|
|
1885
1890
|
|
|
1886
1891
|
function applyAiConversationTaskType(taskType) {
|
|
@@ -1899,7 +1904,6 @@ function applyAiConversationContextScope(scope) {
|
|
|
1899
1904
|
: normalizedScope.type === "chapter" && normalizedScope.includeBookSummary ? "chapter-summary"
|
|
1900
1905
|
: normalizedScope.type === "chapter" ? "chapter"
|
|
1901
1906
|
: "none";
|
|
1902
|
-
$("#ai-include-setting-info").checked = normalizedScope.includeSettingInfo !== false;
|
|
1903
1907
|
syncAiTaskOptions();
|
|
1904
1908
|
}
|
|
1905
1909
|
|
|
@@ -2046,10 +2050,11 @@ function updateAiMentionMenu() {
|
|
|
2046
2050
|
...chapter,
|
|
2047
2051
|
volumeTitle: volume.title
|
|
2048
2052
|
}))) ?? [];
|
|
2049
|
-
const options = listAiMentionOptions(state.characters, state.settings, chapters, match.query)
|
|
2053
|
+
const options = listAiMentionOptions(state.characters, state.settings, chapters, match.query)
|
|
2054
|
+
.filter((item) => item.kind !== "context-settings" || $("#ai-task").value !== "roleplay");
|
|
2050
2055
|
menu.innerHTML = options.length
|
|
2051
2056
|
? options.map((item) => `<button class="ai-mention-option" type="button" role="option" data-ai-reference-kind="${esc(item.kind)}" data-ai-reference-id="${esc(item.id)}" data-ai-reference-name="${esc(item.name)}"><small>${esc(item.kindLabel)}</small><strong>${esc(item.name)}</strong></button>`).join("")
|
|
2052
|
-
: '<p class="ai-mention-empty"
|
|
2057
|
+
: '<p class="ai-mention-empty">没有匹配的角色、设定、章节或上下文能力</p>';
|
|
2053
2058
|
menu.classList.remove("hidden");
|
|
2054
2059
|
}
|
|
2055
2060
|
|
|
@@ -2271,7 +2276,7 @@ function clearChapterLineSelection() {
|
|
|
2271
2276
|
}
|
|
2272
2277
|
|
|
2273
2278
|
const typographyStorageKey = "ai-novel-typography-v1";
|
|
2274
|
-
const typographyDefaults = Object.freeze({ cjkFont: "system", latinFont: "system", fontSize: 17, uiFontSize:
|
|
2279
|
+
const typographyDefaults = Object.freeze({ cjkFont: "system", latinFont: "system", fontSize: 17, uiFontSize: 14, aiFontSize: 14, density: "balanced" });
|
|
2275
2280
|
const cjkFontStacks = {
|
|
2276
2281
|
system: '"PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", "Heiti SC"',
|
|
2277
2282
|
pingfang: '"PingFang SC", "Heiti SC", "Microsoft YaHei", "Noto Sans CJK SC"',
|
|
@@ -4124,6 +4129,9 @@ function resetWorkScopedUiCaches() {
|
|
|
4124
4129
|
Object.keys(moduleListPages).forEach((key) => { moduleListPages[key] = 1; });
|
|
4125
4130
|
relationshipFilters.fromCharacterIds = [];
|
|
4126
4131
|
relationshipFilters.toCharacterIds = [];
|
|
4132
|
+
timelineActiveTrackId = null;
|
|
4133
|
+
timelineSortDirection = "asc";
|
|
4134
|
+
timelineMultiSelectEnabled = false;
|
|
4127
4135
|
taskListPage = 1;
|
|
4128
4136
|
state.collapsedVolumeIds.clear();
|
|
4129
4137
|
loadedVolumeChapterIds.clear();
|
|
@@ -5363,6 +5371,10 @@ function renderSettingRows(records) {
|
|
|
5363
5371
|
}).join("")}</div>`;
|
|
5364
5372
|
}
|
|
5365
5373
|
|
|
5374
|
+
function entityLifecycleBadge(active, label) {
|
|
5375
|
+
return active ? `<span class="entity-lifecycle-badge">${esc(label)}</span>` : "";
|
|
5376
|
+
}
|
|
5377
|
+
|
|
5366
5378
|
async function renderSettings(page = moduleListPages.settings) {
|
|
5367
5379
|
const records = await moduleApiAllPages("settings", `/api/works/${state.work.id}/settings`);
|
|
5368
5380
|
state.settings = records;
|
|
@@ -5408,7 +5420,7 @@ async function renderCharacters(page = characterListPage) {
|
|
|
5408
5420
|
const details = normalizeCharacterDetails(item.attributes?.details);
|
|
5409
5421
|
return `
|
|
5410
5422
|
<article class="record-card character-card preview-record-card has-card-edit" data-open-character="${esc(item.id)}" role="button" tabindex="0" aria-label="查看角色 ${esc(item.name)}">${recordCardEditButton("edit-character", item.id, `角色“${item.name}”`)}
|
|
5411
|
-
<div class="character-card-heading"><h3>${esc(item.name)}</h3>${characterLockBadge(item)}</div>
|
|
5423
|
+
<div class="character-card-heading"><h3>${esc(item.name)}</h3>${entityLifecycleBadge(item.isDead, "已死亡")}${characterLockBadge(item)}</div>
|
|
5412
5424
|
${item.attributes?.identity ? `<p class="character-identity">${esc(item.attributes.identity)}</p>` : ""}
|
|
5413
5425
|
${item.aliases.length ? `<div class="character-aliases"><b>别名</b>${item.aliases.map((alias) => `<span class="pill">${esc(alias)}</span>`).join("")}</div>` : ""}
|
|
5414
5426
|
${item.code ? `<div class="character-code"><b>编号</b><span class="pill">${esc(item.code)}</span></div>` : ""}
|
|
@@ -5430,7 +5442,7 @@ async function renderCharacters(page = characterListPage) {
|
|
|
5430
5442
|
const line = meta ? `${meta} · ${preview}` : preview;
|
|
5431
5443
|
return `
|
|
5432
5444
|
<article class="record-card module-row character-row character-card preview-record-card" data-open-character="${esc(item.id)}" role="button" tabindex="0" aria-label="查看角色 ${esc(item.name)}">
|
|
5433
|
-
<div class="character-card-heading"><h3>${esc(item.name)}</h3>${characterLockBadge(item)}</div>
|
|
5445
|
+
<div class="character-card-heading"><h3>${esc(item.name)}</h3>${entityLifecycleBadge(item.isDead, "已死亡")}${characterLockBadge(item)}</div>
|
|
5434
5446
|
<p class="module-row-preview" title="${esc(line)}">${esc(line)}</p>
|
|
5435
5447
|
<div class="card-actions">${characterActions(item)}</div>
|
|
5436
5448
|
</article>`;
|
|
@@ -5508,7 +5520,7 @@ function renderRaceCollection(total, descendantsLoading = false) {
|
|
|
5508
5520
|
? raceActions(item)
|
|
5509
5521
|
: `<div class="card-actions">${raceActions(item)}</div>`;
|
|
5510
5522
|
const renderRaceNode = (item) => `<details class="race-tree-node"${state.collapsedRaceIds.has(item.id) ? "" : " open"} data-race-node="${esc(item.id)}">
|
|
5511
|
-
<summary><span>${esc(item.name)}</span><small>${directChildCount(item)} 个直接子种族</small></summary>
|
|
5523
|
+
<summary><span>${esc(item.name)}${entityLifecycleBadge(item.isExtinct, "已灭绝")}</span><small>${directChildCount(item)} 个直接子种族</small></summary>
|
|
5512
5524
|
<div class="race-tree-branch">
|
|
5513
5525
|
<article class="record-card race-card preview-record-card${canEditRaces ? " has-card-edit" : ""}" data-open-race="${esc(item.id)}" role="button" tabindex="0" aria-label="查看种族 ${esc(item.name)}"><small>${item.memberIds.length} 位直接角色 · ${item.settingsCount ?? item.settings?.length ?? 0} 条自身设定</small>
|
|
5514
5526
|
<div class="race-path" aria-label="种族路径">${esc(racePathLabel(item))}</div>
|
|
@@ -5526,7 +5538,7 @@ function renderRaceCollection(total, descendantsLoading = false) {
|
|
|
5526
5538
|
return `
|
|
5527
5539
|
<article class="record-card module-row race-card preview-record-card" data-open-race="${esc(item.id)}" role="button" tabindex="0" aria-label="查看种族 ${esc(item.name)}">
|
|
5528
5540
|
<small>${esc(meta)}</small>
|
|
5529
|
-
<h3>${esc(item.name)}<span class="module-row-path">${esc(racePathLabel(item))}</span></h3>
|
|
5541
|
+
<h3>${esc(item.name)}${entityLifecycleBadge(item.isExtinct, "已灭绝")}<span class="module-row-path">${esc(racePathLabel(item))}</span></h3>
|
|
5530
5542
|
<p class="module-row-preview" title="${esc(preview)}">${esc(preview)}${item.members.length ? ` · ${esc(item.members.map((member) => member.name).join("、"))}` : ""}</p>
|
|
5531
5543
|
<div class="card-actions">${raceActions(item)}</div>
|
|
5532
5544
|
</article>`;
|
|
@@ -5613,7 +5625,7 @@ async function renderOrganizations(page = moduleListPages.organizations) {
|
|
|
5613
5625
|
: `<div class="card-actions">${organizationActions(item)}</div>`;
|
|
5614
5626
|
const organizationCards = () => `<div class="card-grid organization-grid">${pageResult.items.map((item) => `
|
|
5615
5627
|
<article class="record-card organization-card preview-record-card${canEditOrganizations ? " has-card-edit" : ""}" data-open-organization="${esc(item.id)}" role="button" tabindex="0" aria-label="查看组织 ${esc(item.name)}"><small>${item.memberIds.length} 位成员 · ${(item.settingsCount ?? item.settings?.length ?? 0) ? "已填写组织设定" : "暂无组织设定"}</small>
|
|
5616
|
-
<h3>${esc(item.name)}</h3><p>${esc(item.description || "尚未填写组织简介")}</p>
|
|
5628
|
+
<h3>${esc(item.name)}${entityLifecycleBadge(item.isDissolved, "已解散")}</h3><p>${esc(item.description || "尚未填写组织简介")}</p>
|
|
5617
5629
|
<div class="organization-settings">${item.settingsCount ? `<span class="pill">${item.settingsCount} 条组织设定,打开查看详情</span>` : '<span class="pill">暂无组织设定</span>'}</div>
|
|
5618
5630
|
<p class="organization-members">成员:${item.members.length ? item.members.map((member) => esc(member.name)).join("、") : "暂无绑定角色"}</p>
|
|
5619
5631
|
${organizationCardActions(item)}
|
|
@@ -5624,7 +5636,7 @@ async function renderOrganizations(page = moduleListPages.organizations) {
|
|
|
5624
5636
|
return `
|
|
5625
5637
|
<article class="record-card module-row organization-card" data-open-organization="${esc(item.id)}" role="button" tabindex="0" aria-label="查看组织 ${esc(item.name)}">
|
|
5626
5638
|
<small>${item.memberIds.length} 位成员 · ${(item.settingsCount ?? item.settings?.length ?? 0) ? "已填写组织设定" : "暂无组织设定"}</small>
|
|
5627
|
-
<h3>${esc(item.name)}</h3>
|
|
5639
|
+
<h3>${esc(item.name)}${entityLifecycleBadge(item.isDissolved, "已解散")}</h3>
|
|
5628
5640
|
<p class="module-row-preview" title="${esc(`${preview} · 成员:${members}`)}">${esc(preview)} · ${esc(members)}</p>
|
|
5629
5641
|
<div class="card-actions">${organizationActions(item)}</div>
|
|
5630
5642
|
</article>`;
|
|
@@ -5667,24 +5679,63 @@ async function renderTimeline(page = moduleListPages.timeline) {
|
|
|
5667
5679
|
moduleApiAllPages("timeline", `/api/works/${state.work.id}/timeline`),
|
|
5668
5680
|
moduleApiAllPages("timeline", `/api/works/${state.work.id}/timeline-tracks`)
|
|
5669
5681
|
]);
|
|
5670
|
-
|
|
5671
|
-
const
|
|
5682
|
+
state.timelineTracks = tracks;
|
|
5683
|
+
const orderedTracks = [...tracks].sort((left, right) => {
|
|
5684
|
+
const orderDelta = Number(left.sortOrder ?? 0) - Number(right.sortOrder ?? 0);
|
|
5685
|
+
if (orderDelta !== 0) return orderDelta;
|
|
5686
|
+
return String(left.id).localeCompare(String(right.id));
|
|
5687
|
+
});
|
|
5688
|
+
const tabTracks = [
|
|
5689
|
+
...orderedTracks,
|
|
5690
|
+
{ id: "", name: "未分组", description: "尚未归入独立时间轴的时间节点。" }
|
|
5691
|
+
];
|
|
5692
|
+
timelineActiveTrackId = resolveTimelineActiveTrackId(timelineActiveTrackId, tracks);
|
|
5693
|
+
timelineSortDirection = normalizeTimelineSortDirection(timelineSortDirection);
|
|
5694
|
+
const activeTrack = tabTracks.find((track) => String(track.id ?? "") === String(timelineActiveTrackId)) ?? tabTracks[tabTracks.length - 1];
|
|
5695
|
+
const filteredEvents = prepareTimelineEvents(events, { trackIds: [timelineActiveTrackId] }, { direction: timelineSortDirection });
|
|
5696
|
+
mountModuleCount(filteredEvents.length);
|
|
5697
|
+
const pageResult = paginateModuleItems(filteredEvents, page, "timeline");
|
|
5672
5698
|
moduleListPages.timeline = pageResult.page;
|
|
5673
5699
|
timelineMultiSelectEnabled = false;
|
|
5674
5700
|
$("#timeline-tools")?.remove();
|
|
5701
|
+
$("#module-header-actions").querySelector('[data-module-header-action="timeline-filter-toggle"]')?.remove();
|
|
5675
5702
|
$("#module-header-actions").insertAdjacentHTML("beforeend", `<div id="timeline-tools" class="timeline-tools" data-module-header-action="timeline-tools" role="group" aria-label="时间轴操作"><button id="create-timeline-track" class="ghost-button" type="button">新建独立时间轴</button><button id="timeline-multi-select-toggle" class="ghost-button" type="button" aria-pressed="false">多选</button>${events.length > 1 ? '<button id="merge-events" class="ghost-button" type="button" hidden>合并所选事件</button>' : ""}</div>`);
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5703
|
+
const tabsMarkup = `<div class="timeline-track-tabs" role="tablist" aria-label="时间轴轨道">${tabTracks.map((track) => {
|
|
5704
|
+
const trackKey = String(track.id ?? "");
|
|
5705
|
+
const selected = trackKey === String(timelineActiveTrackId);
|
|
5706
|
+
const colorIndex = timelineTrackColorIndex(track.id, tracks);
|
|
5707
|
+
return `<button type="button" class="timeline-track-tab" role="tab" id="timeline-track-tab-${esc(trackKey || "ungrouped")}" data-timeline-track-tab="${esc(trackKey)}" data-track-color-index="${colorIndex}" aria-selected="${selected}" aria-controls="timeline-track-panel" tabindex="${selected ? "0" : "-1"}"><span class="timeline-track-swatch" aria-hidden="true"></span><span>${esc(track.name)}</span></button>`;
|
|
5708
|
+
}).join("")}</div>`;
|
|
5709
|
+
const trackManageActions = activeTrack.id
|
|
5710
|
+
? `<button class="timeline-track-menu" data-edit-timeline-track="${esc(activeTrack.id)}" type="button">编辑</button><button class="timeline-track-menu" data-entity-history="timeline-track" data-entity-id="${esc(activeTrack.id)}" data-entity-title="${esc(activeTrack.name)}" type="button">历史</button>`
|
|
5711
|
+
: "";
|
|
5712
|
+
const panelMarkup = `<section id="timeline-track-panel" class="timeline-track-panel" data-track-color-index="${timelineTrackColorIndex(activeTrack.id, tracks)}" role="tabpanel" aria-labelledby="timeline-track-tab-${esc(String(activeTrack.id || "ungrouped"))}"><div class="timeline-track-panel-copy"><strong>${esc(activeTrack.name)}</strong><p>${esc(activeTrack.description || "暂无说明")}</p></div><div class="timeline-track-panel-actions"><div class="timeline-track-actions" role="group" aria-label="当前轨道操作">${trackManageActions}<button class="timeline-track-menu" data-add-event-track="${esc(String(activeTrack.id ?? ""))}" type="button">添加事件</button><button class="timeline-track-menu" data-timeline-sort="asc" type="button" aria-pressed="${timelineSortDirection === "asc"}">正序</button><button class="timeline-track-menu" data-timeline-sort="desc" type="button" aria-pressed="${timelineSortDirection === "desc"}">倒序</button></div></div></section>`;
|
|
5713
|
+
const eventItem = (item) => {
|
|
5714
|
+
const trackKey = item.trackId ?? "";
|
|
5715
|
+
const colorIndex = timelineTrackColorIndex(trackKey, tracks);
|
|
5716
|
+
return `<article class="timeline-item" data-track-color-index="${colorIndex}" data-event-id="${esc(item.id)}"><div class="timeline-card-meta"><input class="timeline-select" type="checkbox" data-event-select="${esc(item.id)}" aria-label="选择 ${esc(item.name)}" hidden><small>${esc(item.timeLabel)} · ${esc(timelineStatusLabel(item.status))}</small></div><h3>${esc(item.name)}</h3><p>${esc(item.description || "暂无说明")}</p>${item.location ? `<span class="timeline-item-location">地点:${esc(item.location)}</span>` : ""}<div class="card-actions"><button data-edit-event="${esc(item.id)}" type="button">编辑与排序</button><button data-split-event="${esc(item.id)}" type="button">拆分</button><button data-entity-history="timeline-event" data-entity-id="${esc(item.id)}" data-entity-title="${esc(item.name)}" type="button">版本历史</button></div></article>`;
|
|
5717
|
+
};
|
|
5718
|
+
const axisMarkup = pageResult.items.length
|
|
5719
|
+
? `<div class="timeline-axis" data-testid="timeline-axis"><div class="timeline-list">${pageResult.items.map(eventItem).join("")}</div></div>`
|
|
5720
|
+
: `<div class="timeline-axis" data-testid="timeline-axis"><div class="empty-state"><b>当前轨道还没有时间节点</b>可以添加事件,或切换到其他轨道查看。</div></div>`;
|
|
5721
|
+
$("#module-content").innerHTML = `${tabsMarkup}${panelMarkup}${axisMarkup}${renderModulePagination(pageResult, "timeline", "时间线事件")}`;
|
|
5683
5722
|
bindModulePagination("timeline", renderTimeline);
|
|
5684
5723
|
$("#create-timeline-track").addEventListener("click", () => openTimelineTrackDialog());
|
|
5685
5724
|
$("#timeline-multi-select-toggle").addEventListener("click", () => setTimelineMultiSelectMode(!timelineMultiSelectEnabled));
|
|
5686
5725
|
$("#module-content").querySelectorAll("[data-event-select]").forEach((input) => input.addEventListener("change", updateTimelineMultiSelectControls));
|
|
5687
5726
|
setTimelineMultiSelectMode(false);
|
|
5727
|
+
$("#module-content").querySelectorAll("[data-timeline-track-tab]").forEach((button) => button.addEventListener("click", async () => {
|
|
5728
|
+
const nextTrackId = button.dataset.timelineTrackTab ?? "";
|
|
5729
|
+
if (String(nextTrackId) === String(timelineActiveTrackId)) return;
|
|
5730
|
+
timelineActiveTrackId = nextTrackId;
|
|
5731
|
+
await renderTimeline(1);
|
|
5732
|
+
}));
|
|
5733
|
+
$("#module-content").querySelectorAll("[data-timeline-sort]").forEach((button) => button.addEventListener("click", async () => {
|
|
5734
|
+
const nextDirection = normalizeTimelineSortDirection(button.dataset.timelineSort);
|
|
5735
|
+
if (nextDirection === timelineSortDirection) return;
|
|
5736
|
+
timelineSortDirection = nextDirection;
|
|
5737
|
+
await renderTimeline(1);
|
|
5738
|
+
}));
|
|
5688
5739
|
$("#module-content").querySelectorAll("[data-edit-timeline-track]").forEach((button) => button.addEventListener("click", () => openTimelineTrackDialog(tracks.find((track) => track.id === button.dataset.editTimelineTrack))));
|
|
5689
5740
|
$("#module-content").querySelectorAll("[data-add-event-track]").forEach((button) => button.addEventListener("click", () => openTimelineDialog(null, button.dataset.addEventTrack || null)));
|
|
5690
5741
|
$("#module-content").querySelectorAll("[data-edit-event]").forEach((button) => button.addEventListener("click", () => openTimelineDialog(events.find((item) => item.id === button.dataset.editEvent))));
|
|
@@ -7216,6 +7267,7 @@ async function renderBookAiSettings() {
|
|
|
7216
7267
|
title: "本书 Token 用量",
|
|
7217
7268
|
description: `仅统计《${state.work.title}》迄今产生的 AI Token 消耗与缓存命中情况。`
|
|
7218
7269
|
})}</section><section class="config-section"><div class="config-section-header"><div><h2>每日 Token 额度</h2><p>限制本书在后端部署时区(${esc(quotaTimezone)})每个自然日可使用的输入与输出 Token 总量。额度最低为 10,000;达到额度后,新的 AI 请求会等到后端时区的次日零点重置后再执行。</p></div></div><div class="config-inline-save"><label><input id="daily-token-quota-enabled" type="checkbox" ${dailyTokenQuota === null ? "" : "checked"}>启用每日额度</label><label class="daily-token-quota-field">每日额度<input id="daily-token-quota" type="number" min="10000" max="2000000000" step="1000" value="${esc(String(dailyTokenQuota ?? 10000))}" aria-label="本书每日 Token 额度" ${dailyTokenQuota === null ? "disabled" : ""}></label><button id="save-daily-token-quota" class="ghost-button config-save-button" type="button">保存</button></div><p id="daily-token-quota-status" class="usage-measurement-note" role="status">${esc(quotaStatusText)}</p></section><section class="config-section"><div class="config-section-header"><div><h2>本书系统提示词</h2><p>会追加在内置系统提示词和平台全局系统提示词之后,只影响《${esc(state.work.title)}》的 AI 请求。</p></div></div><div class="field-label"><textarea id="work-system-prompt" rows="8" aria-label="本书系统提示词" placeholder="例如:叙事使用第三人称,哥斯拉不得离开地球。">${esc(settings.systemPrompt)}</textarea></div><div class="card-actions"><button id="save-work-system-prompt" class="ghost-button config-save-button" type="button">保存本书提示词</button></div></section><section class="config-section"><div class="config-section-header"><div><h2>人物关系拼音索引</h2><p>平时由系统记录增量任务;“同步增量队列”只处理发生变化的来源,“完整重建索引”会将本书全部正文和设定来源重新排队。</p></div></div><div id="relationship-search-index-status" role="status" aria-live="polite">${relationshipIndexStatusMarkup(relationshipIndex)}</div><div class="relationship-index-actions"><button id="sync-relationship-search-index" class="primary-button config-save-button" type="button">同步增量队列</button><button id="refresh-relationship-search-index" class="ghost-button" type="button">刷新状态</button><button id="rebuild-relationship-search-index" class="ghost-button config-save-button" type="button">完整重建索引</button></div></section><section class="config-section"><div class="config-section-header"><div><h2>全书概要引用配额</h2><p>引用全书概要时按分卷保留覆盖,并优先加入与当前问题相关的章节概要;该比例控制概要可使用的上下文预算。</p></div></div><div class="config-inline-save"><label class="book-summary-context-percent-field">上下文占比(%)<input id="book-summary-context-percent" type="number" min="1" max="90" value="${esc(String(settings.bookSummaryContextPercent ?? 50))}" aria-label="全书概要引用上下文占比"></label><button id="save-book-summary-context-percent" class="ghost-button config-save-button" type="button">保存</button></div></section><section class="config-section"><div class="config-section-header"><div><h2>对话上下文 Compact</h2><p>对话 context 使用独立预算。达到该百分比阈值时先提醒;继续发送会对较早消息执行 compact,压缩上下文占用,并尽量保留最近八条原文。</p></div></div><div class="config-inline-save"><label class="context-compact-threshold-field">Compact 阈值(%)<input id="context-compact-threshold" type="number" min="50" max="90" value="${esc(String(settings.contextCompactThreshold ?? 85))}" aria-label="对话上下文 compact 阈值"></label><button id="save-context-compact-threshold" class="ghost-button config-save-button" type="button">保存</button></div></section><section class="config-section"><div class="config-section-header"><div><h2>Agent 工具调用上限</h2><p>限制单次回答里 Agent 可调用工具的次数,并用「全局倍数」给整次回答加一道不会因 Compact 重置的熔断阀,防止工具死循环空耗 Token。调用上限 5–48(默认 12);全局倍数 1–6(默认 3,全局上限 = 调用上限 × 倍数)。<a class="config-doc-link" href="https://scriverse.top/docs/global-tool-call-limit.html" target="_blank" rel="noopener noreferrer">了解原理与推荐设置</a></p></div></div><div class="config-inline-save"><label class="agent-tool-call-limit-field">调用上限<input id="agent-tool-call-limit" type="number" min="5" max="48" value="${esc(String(settings.agentToolCallLimit ?? 12))}" aria-label="Agent 工具调用上限"></label><div class="agent-tool-call-global-multiplier-field"><span id="agent-tool-call-global-multiplier-label">全局倍数</span><div class="settings-layout-toggle agent-tool-call-global-multiplier-toggle" role="group" aria-labelledby="agent-tool-call-global-multiplier-label">${[1, 2, 3, 4, 5, 6].map((value) => `<button type="button" data-global-multiplier="${value}" aria-pressed="${Number(settings.agentToolCallGlobalMultiplier ?? 3) === value}">${value}</button>`).join("")}</div><input id="agent-tool-call-global-multiplier" type="hidden" value="${esc(String(Math.min(6, Math.max(1, Number(settings.agentToolCallGlobalMultiplier ?? 3) || 3))))}" aria-label="Agent 工具调用全局倍数"></div><button id="save-agent-tool-call-limit" class="ghost-button config-save-button" type="button">保存</button></div></section><section class="config-section"><div class="config-section-header"><div><h2>AI 查询工具</h2><p>工具默认可用,作为已有上下文的补充。关闭后模型不会看到对应能力;所有工具只读且有数量、篇幅与调用轮次限制。已开始的对话会锁定创建时的工具集,修改后仅对新对话生效,避免打断 prompt cache。</p></div></div><div class="ai-agent-tools"><label><input name="agent-tool" type="checkbox" value="story_index" ${agentTools.has("story_index") ? "checked" : ""}><span><strong>作品目录与章节概要</strong><small>分页获取卷章、章节 ID 和当前概要,不返回正文。</small></span></label><label><input name="agent-tool" type="checkbox" value="read_chapters" ${agentTools.has("read_chapters") ? "checked" : ""}><span><strong>读取章节</strong><small>按章节 ID 获取概要或正文,每次最多 3 章。</small></span></label><label><input name="agent-tool" type="checkbox" value="search_story_entities" ${agentTools.has("search_story_entities") ? "checked" : ""}><span><strong>搜索作品实体</strong><small>按实体名、拼音或短关键词混合检索设定、人物、组织、时间线、关系、大纲和伏笔;非语义问答。</small></span></label></div><div class="card-actions"><button id="save-agent-tools" class="ghost-button config-save-button" type="button">保存工具设置</button></div></section>${renderTaskDefaults(models, providers, taskDefaults, settings)}`;
|
|
7270
|
+
$("#daily-token-quota-status").closest(".config-section").insertAdjacentHTML("afterend", `<section class="config-section"><div class="config-section-header"><div><h2>设定上下文注入</h2><p>开启后,本书的普通 AI 请求会自动注入锁定设定、组织、种族与相关约束;即使本轮同时使用“@注入上下文设定”,也只会注入一次。</p></div></div><div class="config-inline-save"><label><input id="always-include-setting-info" type="checkbox" ${settings.alwaysIncludeSettingInfo ? "checked" : ""}>是否注入设定</label><button id="save-always-include-setting-info" class="ghost-button config-save-button" type="button">保存</button></div></section>`);
|
|
7219
7271
|
bindUsageCalendarInteractions(host);
|
|
7220
7272
|
scrollUsageCalendarsToLatest(host);
|
|
7221
7273
|
host.querySelector('input[name="agent-tool"][value="search_story_entities"]').closest("label").insertAdjacentHTML(
|
|
@@ -7287,6 +7339,20 @@ async function renderBookAiSettings() {
|
|
|
7287
7339
|
button.disabled = false;
|
|
7288
7340
|
}
|
|
7289
7341
|
});
|
|
7342
|
+
$("#save-always-include-setting-info").addEventListener("click", async () => {
|
|
7343
|
+
const button = $("#save-always-include-setting-info");
|
|
7344
|
+
button.disabled = true;
|
|
7345
|
+
try {
|
|
7346
|
+
const alwaysIncludeSettingInfo = $("#always-include-setting-info").checked;
|
|
7347
|
+
await api(`/api/works/${state.work.id}/ai-settings`, { method: "PATCH", body: { alwaysIncludeSettingInfo } });
|
|
7348
|
+
toast(alwaysIncludeSettingInfo ? "已开启全局设定上下文注入" : "已关闭全局设定上下文注入");
|
|
7349
|
+
setAiContextMeter(null);
|
|
7350
|
+
} catch (error) {
|
|
7351
|
+
toast(error.message, "error");
|
|
7352
|
+
} finally {
|
|
7353
|
+
button.disabled = false;
|
|
7354
|
+
}
|
|
7355
|
+
});
|
|
7290
7356
|
$("#save-work-system-prompt").addEventListener("click", async () => {
|
|
7291
7357
|
const button = $("#save-work-system-prompt");
|
|
7292
7358
|
button.disabled = true;
|
|
@@ -7472,22 +7538,6 @@ async function ensureAiModelsLoaded() {
|
|
|
7472
7538
|
}
|
|
7473
7539
|
}
|
|
7474
7540
|
|
|
7475
|
-
function syncAiIncludeSettingInfoControl() {
|
|
7476
|
-
const scopeType = $("#ai-scope").value;
|
|
7477
|
-
const checkbox = $("#ai-include-setting-info");
|
|
7478
|
-
const proseScopes = new Set(["chapter", "chapter-summary", "volume", "book"]);
|
|
7479
|
-
const enabled = proseScopes.has(scopeType);
|
|
7480
|
-
const roleplaySelected = $("#ai-task").value === "roleplay";
|
|
7481
|
-
checkbox.disabled = roleplaySelected || state.aiPromptSent || !enabled;
|
|
7482
|
-
checkbox.title = state.aiPromptSent
|
|
7483
|
-
? "对话开始后不能切换上下文选项"
|
|
7484
|
-
: enabled
|
|
7485
|
-
? "在正文上下文中注入锁定设定、组织/种族简表等"
|
|
7486
|
-
: scopeType === "settings-catalog"
|
|
7487
|
-
? "设定库范围会直接注入设定目录,无需此选项"
|
|
7488
|
-
: "仅在选择正文类上下文范围时可用";
|
|
7489
|
-
}
|
|
7490
|
-
|
|
7491
7541
|
function currentAiRequestScope() {
|
|
7492
7542
|
if (!state.work) return null;
|
|
7493
7543
|
const selectedTaskType = $("#ai-task").value;
|
|
@@ -7495,6 +7545,7 @@ function currentAiRequestScope() {
|
|
|
7495
7545
|
const taskType = roleplaySelected ? "chat" : selectedTaskType;
|
|
7496
7546
|
if (state.aiPromptSent) {
|
|
7497
7547
|
const conversationScope = JSON.parse(JSON.stringify(state.aiContextScope ?? { type: "none" }));
|
|
7548
|
+
conversationScope.includeSettingInfo = false;
|
|
7498
7549
|
const scope = mergeAiReferenceScope(conversationScope, state.aiReferences);
|
|
7499
7550
|
return { taskType, scope, conversationScope, selection: typeof conversationScope.selection === "string" ? conversationScope.selection : "" };
|
|
7500
7551
|
}
|
|
@@ -7511,10 +7562,7 @@ function currentAiRequestScope() {
|
|
|
7511
7562
|
: scopeType === "settings-catalog" ? { type: "settings-catalog" }
|
|
7512
7563
|
: { type: "chapter", chapterId: state.chapter?.id };
|
|
7513
7564
|
if (includeBookSummary) conversationScope.includeBookSummary = true;
|
|
7514
|
-
|
|
7515
|
-
if (proseScopes.has(scopeType) || taskType === "polish") {
|
|
7516
|
-
conversationScope.includeSettingInfo = $("#ai-include-setting-info").checked;
|
|
7517
|
-
}
|
|
7565
|
+
conversationScope.includeSettingInfo = false;
|
|
7518
7566
|
const scope = mergeAiReferenceScope(conversationScope, state.aiReferences);
|
|
7519
7567
|
return { taskType, scope, conversationScope, selection };
|
|
7520
7568
|
}
|
|
@@ -8947,6 +8995,7 @@ function renderCharacterEditorFields(item) {
|
|
|
8947
8995
|
$("#character-editor-fields").innerHTML = [
|
|
8948
8996
|
characterEditorSection("basic", "基础资料", "用于检索、去重和建立人物在作品中的基本归属。",
|
|
8949
8997
|
field("name", "标准名", "text", item?.name) +
|
|
8998
|
+
field("isDead", "标记为已死亡", "checkbox", item?.isDead ?? false) +
|
|
8950
8999
|
field("aliases", "别名", "item-list", item?.aliases ?? []) +
|
|
8951
9000
|
(!canReadModule("races")
|
|
8952
9001
|
? '<div class="character-editor-empty-field"><b>种族</b><span>当前账户没有种族模块读取权限,原有绑定不会被修改。</span></div>'
|
|
@@ -8999,6 +9048,7 @@ function collectCharacterBody(form) {
|
|
|
8999
9048
|
delete profile.sections;
|
|
9000
9049
|
const body = {
|
|
9001
9050
|
name: String(form.get("name") ?? "").trim(),
|
|
9051
|
+
isDead: form.has("isDead"),
|
|
9002
9052
|
code: String(form.get("code") ?? "").trim(),
|
|
9003
9053
|
aliases: form.getAll("aliases").map((value) => String(value).trim()).filter(Boolean),
|
|
9004
9054
|
attributes: {
|
|
@@ -9207,7 +9257,10 @@ function renderKnowledgeEditorFields(kind, item, memberOptions, parentOptions) {
|
|
|
9207
9257
|
? [["basic", "基础资料", "名称、层级与简介"], ["settings", "共同设定", "Markdown 设定章节"], ["members", "种族成员", "角色归属"]]
|
|
9208
9258
|
: [["basic", "基础资料", "名称与简介"], ["settings", "组织设定", "Markdown 设定章节"], ["members", "组织成员", "角色归属"]];
|
|
9209
9259
|
$("#knowledge-editor-nav").innerHTML = tabs.map(([key, tabTitle, description], index) => `<button type="button" role="tab" data-knowledge-editor-tab="${key}" aria-selected="${index === 0}" tabindex="${index === 0 ? "0" : "-1"}">${tabTitle}<small>${description}</small></button>`).join("");
|
|
9210
|
-
const basicFields = field("name", `${label}名称`, "text", item?.name, [])
|
|
9260
|
+
const basicFields = field("name", `${label}名称`, "text", item?.name, [])
|
|
9261
|
+
+ field(isRace ? "isExtinct" : "isDissolved", isRace ? "标记为已灭绝" : "标记为已解散", "checkbox", isRace ? item?.isExtinct ?? false : item?.isDissolved ?? false)
|
|
9262
|
+
+ (isRace ? field("parentRaceId", "父种族", "select", item?.parentRaceId ?? "", parentOptions) : "")
|
|
9263
|
+
+ field("description", `${label}简介`, "textarea", item?.description, []);
|
|
9211
9264
|
const memberField = memberOptions.length
|
|
9212
9265
|
? field("memberIds", isRace ? "属于该种族的角色(可多选)" : "组织成员(可多选)", "chips", item?.memberIds ?? [], memberOptions)
|
|
9213
9266
|
: `<div class="character-editor-empty-field"><strong>${isRace ? "种族成员" : "组织成员"}</strong><span>当前还没有可绑定的角色。</span></div>`;
|
|
@@ -9313,8 +9366,8 @@ async function openKnowledgeEditor(kind, item, { readOnly = false } = {}) {
|
|
|
9313
9366
|
if (untitled >= 0) throw new Error(`请填写第 ${untitled + 1} 条 Markdown 设定的标题`);
|
|
9314
9367
|
const settingsMarkdown = settingsSections.map((section) => section.contentMarkdown).join("\n\n");
|
|
9315
9368
|
const body = isRace
|
|
9316
|
-
? { name, parentRaceId: data.get("parentRaceId") || null, description: data.get("description"), settingsMarkdown, settingsSections }
|
|
9317
|
-
: { name, description: data.get("description"), settingsMarkdown, settingsSections };
|
|
9369
|
+
? { name, isExtinct: data.has("isExtinct"), parentRaceId: data.get("parentRaceId") || null, description: data.get("description"), settingsMarkdown, settingsSections }
|
|
9370
|
+
: { name, isDissolved: data.has("isDissolved"), description: data.get("description"), settingsMarkdown, settingsSections };
|
|
9318
9371
|
if (canReadModule("characters")) body.memberIds = data.getAll("memberIds").map(String);
|
|
9319
9372
|
const wasEditing = Boolean(knowledgeEditorItem);
|
|
9320
9373
|
if (!(await confirmConcurrentSave())) return;
|
|
@@ -9343,7 +9396,7 @@ async function openOrganizationDialog(item, options) {
|
|
|
9343
9396
|
}
|
|
9344
9397
|
|
|
9345
9398
|
function openTimelineTrackDialog(item) {
|
|
9346
|
-
openDialog(item ? "编辑独立时间轴" : "新建独立时间轴", field("name", "时间轴名称", "text", item?.name) + field("description", "时间轴简介", "textarea", item?.description) + field("sortOrder", "
|
|
9399
|
+
openDialog(item ? "编辑独立时间轴" : "新建独立时间轴", field("name", "时间轴名称", "text", item?.name) + field("description", "时间轴简介", "textarea", item?.description) + field("sortOrder", "轨道排序", "number", item?.sortOrder ?? state.timelineTracks.length), async (form) => {
|
|
9347
9400
|
await api(item ? `/api/timeline-tracks/${item.id}` : `/api/works/${state.work.id}/timeline-tracks`, { method: item ? "PATCH" : "POST", body: { name: form.get("name"), description: form.get("description"), sortOrder: Number(form.get("sortOrder")) } });
|
|
9348
9401
|
await renderTimeline();
|
|
9349
9402
|
}, item ? "大事件分组" : "多线叙事");
|
|
@@ -11618,11 +11671,8 @@ $("#ai-scope").addEventListener("change", (event) => {
|
|
|
11618
11671
|
return toast("当前对话已经开始,请新建对话后再切换上下文引用", "error");
|
|
11619
11672
|
}
|
|
11620
11673
|
event.currentTarget.title = "";
|
|
11621
|
-
syncAiIncludeSettingInfoControl();
|
|
11622
11674
|
setAiContextMeter(null);
|
|
11623
11675
|
});
|
|
11624
|
-
$("#ai-include-setting-info").addEventListener("change", () => setAiContextMeter(null));
|
|
11625
|
-
syncAiIncludeSettingInfoControl();
|
|
11626
11676
|
$("#ai-mention-menu").addEventListener("click", (event) => {
|
|
11627
11677
|
const button = event.target.closest("[data-ai-reference-id]");
|
|
11628
11678
|
if (button) selectAiMention(button);
|
package/dist/public/index.html
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<link rel="icon" href="/icon.svg?v=20260712" type="image/svg+xml">
|
|
11
11
|
<link rel="manifest" href="/site.webmanifest">
|
|
12
12
|
<link rel="stylesheet" href="/vendor/vditor/dist/index.css?v=3.11.2">
|
|
13
|
-
|
|
13
|
+
<link rel="stylesheet" href="/styles.css?v=20260801-ui-font-scale-shelf-v3">
|
|
14
14
|
</head>
|
|
15
15
|
<body class="auth-pending">
|
|
16
16
|
<section id="auth-view" class="auth-view hidden" aria-labelledby="auth-title">
|
|
@@ -321,17 +321,13 @@
|
|
|
321
321
|
<select id="ai-roleplay-character" class="ai-roleplay-character hidden" aria-label="角色扮演角色卡">
|
|
322
322
|
<option value="">选择角色卡</option>
|
|
323
323
|
</select>
|
|
324
|
-
<label class="ai-include-setting-info" for="ai-include-setting-info">
|
|
325
|
-
<input id="ai-include-setting-info" type="checkbox" checked>
|
|
326
|
-
<span>注入设定信息</span>
|
|
327
|
-
</label>
|
|
328
324
|
</div>
|
|
329
325
|
<div class="field-label prompt-model-field">
|
|
330
326
|
<select id="ai-model" aria-label="实际使用模型"></select>
|
|
331
327
|
</div>
|
|
332
328
|
<div class="prompt-composer">
|
|
333
329
|
<div id="ai-prompt" class="ai-prompt" contenteditable="true" role="textbox" aria-multiline="true" aria-keyshortcuts="Enter" title="Enter 发送,Shift+Enter 换行" data-placeholder="告诉 AI 你想讨论或修改什么……"></div>
|
|
334
|
-
<div id="ai-mention-menu" class="ai-mention-menu hidden" role="listbox" aria-label="
|
|
330
|
+
<div id="ai-mention-menu" class="ai-mention-menu hidden" role="listbox" aria-label="引用角色、设定、章节或上下文能力"></div>
|
|
335
331
|
<div class="prompt-composer-actions">
|
|
336
332
|
<button id="ai-context-meter" class="ai-context-meter is-empty" type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="ai-context-popover" aria-live="polite" aria-label="当前上下文用量"><b>—</b></button>
|
|
337
333
|
<section id="ai-context-popover" class="ai-context-popover hidden" role="dialog" aria-labelledby="ai-context-popover-title" aria-describedby="ai-context-popover-description">
|
|
@@ -668,9 +664,9 @@
|
|
|
668
664
|
</label>
|
|
669
665
|
<label>界面字号
|
|
670
666
|
<select id="appearance-ui-font-size" name="uiFontSize">
|
|
671
|
-
<option value="14">14 px
|
|
667
|
+
<option value="14">14 px(标准)</option>
|
|
672
668
|
<option value="15">15 px</option>
|
|
673
|
-
<option value="16">16 px
|
|
669
|
+
<option value="16">16 px</option>
|
|
674
670
|
<option value="17">17 px</option>
|
|
675
671
|
<option value="18">18 px(大)</option>
|
|
676
672
|
</select>
|
|
@@ -708,7 +704,7 @@
|
|
|
708
704
|
<strong>字体预览 Typography 0123</strong>
|
|
709
705
|
<span>中文默认使用黑体,English letters always use monospace.</span>
|
|
710
706
|
<span>第二段用于预览正文的行距与段落密度。</span>
|
|
711
|
-
<span id="font-size-preview">界面
|
|
707
|
+
<span id="font-size-preview">界面 14 px · Agent 对话 14 px</span>
|
|
712
708
|
</div>
|
|
713
709
|
</div>
|
|
714
710
|
<div class="dialog-actions">
|
|
@@ -955,6 +951,6 @@
|
|
|
955
951
|
<div id="auth-loading" class="auth-loading" role="status" aria-label="正在载入工作台"></div>
|
|
956
952
|
<script id="vditorIconScript" src="/vendor/vditor/dist/js/icons/ant.js?v=3.11.2"></script>
|
|
957
953
|
<script src="/vendor/vditor/dist/index.min.js?v=3.11.2"></script>
|
|
958
|
-
<script type="module" src="/app.js?v=20260801-
|
|
954
|
+
<script type="module" src="/app.js?v=20260801-timeline-lifecycle-v1"></script>
|
|
959
955
|
</body>
|
|
960
956
|
</html>
|