@musnows/scriverse 0.7.5 → 0.7.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.
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import JSZip from "jszip";
3
2
  import sharp from "sharp";
3
+ import { createZipStream } from "./zip-stream.js";
4
4
  export const EPUB_MIME_TYPE = "application/epub+zip";
5
5
  const bidiControlCharacters = /[\u202a-\u202e\u2066-\u2069]/gu;
6
6
  const unsafeFileNameCharacters = /[\u0000-\u001f\u007f-\u009f<>:"/\\|?*]/gu;
@@ -237,25 +237,23 @@ export async function createEpubArchive(input) {
237
237
  const identifier = String(input.identifier ?? `urn:uuid:${randomUUID()}`);
238
238
  const modified = normalizeModifiedAt(input.modifiedAt);
239
239
  const cover = input.cover ? await prepareCover(input.cover) : null;
240
- const archive = new JSZip();
241
- const fileOptions = { date: modified.date };
242
- archive.file("mimetype", EPUB_MIME_TYPE, { ...fileOptions, compression: "STORE" });
243
- archive.file("META-INF/container.xml", `<?xml version="1.0" encoding="UTF-8"?>
240
+ const entries = [{ name: "mimetype", content: EPUB_MIME_TYPE, compression: "STORE" }];
241
+ entries.push({ name: "META-INF/container.xml", content: `<?xml version="1.0" encoding="UTF-8"?>
244
242
  <container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0">
245
243
  <rootfiles>
246
244
  <rootfile full-path="OEBPS/package.opf" media-type="application/oebps-package+xml" />
247
245
  </rootfiles>
248
246
  </container>
249
- `, fileOptions);
250
- archive.file("OEBPS/styles/book.css", bookStyles, fileOptions);
247
+ ` });
248
+ entries.push({ name: "OEBPS/styles/book.css", content: bookStyles });
251
249
  if (cover) {
252
- archive.file(`OEBPS/images/cover.${cover.extension}`, cover.content, fileOptions);
253
- archive.file("OEBPS/text/cover.xhtml", xhtmlPage({
254
- language,
255
- title: `${title}封面`,
256
- body: ` <div class="cover-page"><img src="../images/cover.${cover.extension}" alt="${xml(title)}封面" /></div>`,
257
- bodyType: "cover"
258
- }), fileOptions);
250
+ entries.push({ name: `OEBPS/images/cover.${cover.extension}`, content: cover.content });
251
+ entries.push({ name: "OEBPS/text/cover.xhtml", content: xhtmlPage({
252
+ language,
253
+ title: `${title}封面`,
254
+ body: ` <div class="cover-page"><img src="../images/cover.${cover.extension}" alt="${xml(title)}封面" /></div>`,
255
+ bodyType: "cover"
256
+ }) });
259
257
  }
260
258
  const titleBody = ` <section class="title-page" epub:type="titlepage">
261
259
  <h1>${xml(title)}</h1>${author ? `\n <p class="book-author">${xml(author)}</p>` : ""}${description ? `\n <p class="book-description">${xml(description)}</p>` : ""}
@@ -263,57 +261,63 @@ export async function createEpubArchive(input) {
263
261
  const titleDocument = {
264
262
  id: "title-page",
265
263
  href: "text/title.xhtml",
266
- title,
267
- content: xhtmlPage({ language, title, body: titleBody, bodyType: "frontmatter" })
264
+ title
268
265
  };
269
- archive.file(`OEBPS/${titleDocument.href}`, titleDocument.content, fileOptions);
266
+ entries.push({
267
+ name: `OEBPS/${titleDocument.href}`,
268
+ content: xhtmlPage({ language, title, body: titleBody, bodyType: "frontmatter" })
269
+ });
270
270
  const volumeDocuments = input.volumes.map((volume, volumeIndex) => {
271
271
  const volumeNumber = String(volumeIndex + 1).padStart(3, "0");
272
272
  const volumeTitle = String(volume.title ?? "");
273
273
  const volumeDocument = {
274
274
  id: `volume-${volumeNumber}`,
275
275
  href: `text/volume-${volumeNumber}.xhtml`,
276
- title: volumeTitle,
276
+ title: volumeTitle
277
+ };
278
+ entries.push({
279
+ name: `OEBPS/${volumeDocument.href}`,
277
280
  content: xhtmlPage({
278
281
  language,
279
282
  title: volumeTitle,
280
283
  body: ` <section class="volume-page" epub:type="part"><h1>${xml(volumeTitle)}</h1></section>`,
281
284
  bodyType: "bodymatter"
282
285
  })
283
- };
284
- archive.file(`OEBPS/${volumeDocument.href}`, volumeDocument.content, fileOptions);
286
+ });
285
287
  const chapters = volume.chapters.map((chapter, chapterIndex) => {
286
288
  const chapterNumber = String(chapterIndex + 1).padStart(3, "0");
287
289
  const chapterTitle = String(chapter.title ?? "");
288
290
  const chapterDocument = {
289
291
  id: `chapter-${volumeNumber}-${chapterNumber}`,
290
292
  href: `text/chapter-${volumeNumber}-${chapterNumber}.xhtml`,
291
- title: chapterTitle,
292
- content: xhtmlPage({
293
+ title: chapterTitle
294
+ };
295
+ entries.push({
296
+ name: `OEBPS/${chapterDocument.href}`,
297
+ content: () => xhtmlPage({
293
298
  language,
294
299
  title: chapterTitle,
295
- body: ` <article epub:type="chapter">\n <p class="volume-label">${xml(volumeTitle)}</p>\n <h1>${xml(chapterTitle)}</h1>\n${renderChapterBody(chapter.content)}\n </article>`,
300
+ body: ` <article epub:type="chapter">\n <p class="volume-label">${xml(volumeTitle)}</p>\n <h1>${xml(chapterTitle)}</h1>\n${renderChapterBody(typeof chapter.content === "function" ? chapter.content() : chapter.content)}\n </article>`,
296
301
  bodyType: "bodymatter"
297
302
  })
298
- };
299
- archive.file(`OEBPS/${chapterDocument.href}`, chapterDocument.content, fileOptions);
303
+ });
300
304
  return chapterDocument;
301
305
  });
302
306
  return { document: volumeDocument, chapters };
303
307
  });
304
308
  const documents = [titleDocument, ...volumeDocuments.flatMap((volume) => [volume.document, ...volume.chapters])];
305
- archive.file("OEBPS/nav.xhtml", navigationDocument({ title, language, volumes: volumeDocuments, hasCover: Boolean(cover) }), fileOptions);
306
- archive.file("OEBPS/toc.ncx", ncxDocument({ title, identifier, volumes: volumeDocuments }), fileOptions);
307
- archive.file("OEBPS/package.opf", packageDocument({
308
- title,
309
- author,
310
- description,
311
- language,
312
- identifier,
313
- modifiedAt: modified.value,
314
- documents,
315
- cover
316
- }), fileOptions);
317
- return archive;
309
+ entries.push({ name: "OEBPS/nav.xhtml", content: navigationDocument({ title, language, volumes: volumeDocuments, hasCover: Boolean(cover) }) });
310
+ entries.push({ name: "OEBPS/toc.ncx", content: ncxDocument({ title, identifier, volumes: volumeDocuments }) });
311
+ entries.push({ name: "OEBPS/package.opf", content: packageDocument({
312
+ title,
313
+ author,
314
+ description,
315
+ language,
316
+ identifier,
317
+ modifiedAt: modified.value,
318
+ documents,
319
+ cover
320
+ }) });
321
+ return createZipStream(entries, modified.date);
318
322
  }
319
323
  //# sourceMappingURL=epub-export.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"epub-export.js","sourceRoot":"","sources":["../src/epub-export.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"epub-export.js","sourceRoot":"","sources":["../src/epub-export.ts"],"names":[],"mappings":"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"}
@@ -84,9 +84,9 @@ import {
84
84
  } from "/timeline-view.js?v=20260801-timeline-sort-actions-v1";
85
85
  import {
86
86
  normalizeOutlineBoardState,
87
- outlineBoardUnresolvedCount,
88
- prepareOutlineBoard
89
- } from "/outline-board.js?v=20260812-outline-board-v1";
87
+ outlineBoardRequestPath,
88
+ outlineBoardUnresolvedCount
89
+ } from "/outline-board.js?v=20260813-outline-board-page-v1";
90
90
  import { backgroundTaskActivityCount, backgroundTaskPollDelay, collectBackgroundTaskTransitions } from "/background-task-center.js?v=20260810-analysis-task-failed-v1";
91
91
  import { createModuleRequestCache } from "/module-request-cache.js?v=20260730-module-request-cache-v1";
92
92
  import { systemStatusPresentation } from "/system-status.js?v=20260801-system-health-v1";
@@ -1228,6 +1228,7 @@ let settingFiltersPanelOpen = false;
1228
1228
  const outlineBoardFilters = normalizeOutlineBoardState();
1229
1229
  let outlineBoardFiltersPanelOpen = false;
1230
1230
  let outlineBoardRenderRequestId = 0;
1231
+ let outlineBoardSearchTimer = null;
1231
1232
  const relationshipFilters = { fromCharacterIds: [], toCharacterIds: [] };
1232
1233
  let relationshipFiltersPanelOpen = false;
1233
1234
 
@@ -1808,7 +1809,7 @@ function aiAssistantLabel(suffix = "") {
1808
1809
  return suffix ? `${name} · ${suffix}` : name;
1809
1810
  }
1810
1811
 
1811
- function createAiContextCompactionDivider({ kind = "conversation", ariaLabel = "已压缩上下文", title = "" } = {}) {
1812
+ function createAiContextCompactionDivider({ kind = "conversation", ariaLabel = "当前上下文已压缩", title = "" } = {}) {
1812
1813
  const divider = document.createElement("div");
1813
1814
  divider.className = "ai-context-compaction-divider";
1814
1815
  divider.dataset.contextCompaction = kind;
@@ -1816,7 +1817,7 @@ function createAiContextCompactionDivider({ kind = "conversation", ariaLabel = "
1816
1817
  divider.setAttribute("role", "separator");
1817
1818
  divider.setAttribute("aria-label", ariaLabel);
1818
1819
  if (title) divider.title = title;
1819
- divider.innerHTML = "<span>已压缩上下文</span>";
1820
+ divider.innerHTML = "<span>—— 当前上下文已压缩 ——</span>";
1820
1821
  return divider;
1821
1822
  }
1822
1823
 
@@ -5627,6 +5628,8 @@ function resetWorkScopedUiCaches() {
5627
5628
  Object.assign(outlineBoardFilters, normalizeOutlineBoardState());
5628
5629
  outlineBoardFiltersPanelOpen = false;
5629
5630
  outlineBoardRenderRequestId += 1;
5631
+ clearTimeout(outlineBoardSearchTimer);
5632
+ outlineBoardSearchTimer = null;
5630
5633
  chapterSelectionRequestGeneration += 1;
5631
5634
  Object.keys(moduleListPages).forEach((key) => { moduleListPages[key] = 1; });
5632
5635
  relationshipFilters.fromCharacterIds = [];
@@ -8198,16 +8201,17 @@ function bindOutlineBoardCards(board, workId) {
8198
8201
  }));
8199
8202
  }
8200
8203
 
8201
- async function renderOutlines(foreshadowPage = moduleListPages.foreshadows) {
8204
+ async function renderOutlines(foreshadowPage = moduleListPages.foreshadows, boardPage = moduleListPages.outlinePlans) {
8202
8205
  const workId = state.work.id;
8203
8206
  const generation = workScopedUiGeneration;
8204
8207
  const requestId = ++outlineBoardRenderRequestId;
8205
8208
  const currentChapterId = state.chapter?.id;
8209
+ const boardPageSize = pageSizeFor("outlines");
8206
8210
  let board;
8207
8211
  let foreshadows;
8208
8212
  try {
8209
8213
  [board, foreshadows] = await Promise.all([
8210
- moduleApi("outlines", `/api/works/${encodeURIComponent(workId)}/outline-board`),
8214
+ moduleApi("outlines", outlineBoardRequestPath(workId, outlineBoardFilters, boardPage, boardPageSize)),
8211
8215
  moduleApiAllPages("outlines", `/api/works/${encodeURIComponent(workId)}/foreshadows?status=all${currentChapterId ? `&currentChapterId=${encodeURIComponent(currentChapterId)}` : ""}`)
8212
8216
  ]);
8213
8217
  } catch (error) {
@@ -8216,9 +8220,12 @@ async function renderOutlines(foreshadowPage = moduleListPages.foreshadows) {
8216
8220
  }
8217
8221
  if (state.work?.id !== workId || generation !== workScopedUiGeneration || requestId !== outlineBoardRenderRequestId || state.module !== "outlines") return;
8218
8222
 
8219
- if (outlineBoardFilters.volumeId && !board.volumes.some((volume) => String(volume.id) === outlineBoardFilters.volumeId)) {
8223
+ if (outlineBoardFilters.volumeId && !board.volumeOptions.some((volume) => String(volume.id) === outlineBoardFilters.volumeId)) {
8220
8224
  outlineBoardFilters.volumeId = "";
8225
+ board = await moduleApi("outlines", outlineBoardRequestPath(workId, outlineBoardFilters, 1, boardPageSize));
8226
+ if (state.work?.id !== workId || generation !== workScopedUiGeneration || requestId !== outlineBoardRenderRequestId || state.module !== "outlines") return;
8221
8227
  }
8228
+ moduleListPages.outlinePlans = board.page;
8222
8229
  const foreshadowPageResult = paginateModuleItems(foreshadows, foreshadowPage, "outlines");
8223
8230
  moduleListPages.foreshadows = foreshadowPageResult.page;
8224
8231
  const layout = readModuleLayout();
@@ -8254,9 +8261,9 @@ async function renderOutlines(foreshadowPage = moduleListPages.foreshadows) {
8254
8261
 
8255
8262
  const filterState = normalizeOutlineBoardState(outlineBoardFilters);
8256
8263
  Object.assign(outlineBoardFilters, filterState);
8257
- const volumeOptions = board.volumes.map((volume) => `<option value="${esc(volume.id)}" ${filterState.volumeId === String(volume.id) ? "selected" : ""}>${esc(volume.title)}</option>`).join("");
8264
+ const volumeOptions = board.volumeOptions.map((volume) => `<option value="${esc(volume.id)}" ${filterState.volumeId === String(volume.id) ? "selected" : ""}>${esc(volume.title)}</option>`).join("");
8258
8265
  const filterToolbar = `<section id="outline-board-filter-panel" class="character-filter-toolbar outline-board-filter-toolbar${outlineBoardFiltersPanelOpen ? "" : " hidden"}" aria-label="章节大纲看板筛选">
8259
- <label class="setting-filter-field outline-board-search-field" for="outline-board-search"><span>搜索章节与摘要</span><input id="outline-board-search" type="search" value="${esc(filterState.query)}" placeholder="章节、目标、冲突、转折或伏笔" autocomplete="off"></label>
8266
+ <label class="setting-filter-field outline-board-search-field" for="outline-board-search"><span>搜索章节与摘要</span><input id="outline-board-search" type="search" value="${esc(filterState.query)}" placeholder="章节、目标、冲突、转折或伏笔" autocomplete="off" maxlength="200"></label>
8260
8267
  <label class="setting-filter-field" for="outline-board-volume-filter"><span>按分卷筛选</span><select id="outline-board-volume-filter"><option value="">全部分卷</option>${volumeOptions}</select></label>
8261
8268
  <label class="setting-filter-field" for="outline-board-status-filter"><span>按大纲状态筛选</span><select id="outline-board-status-filter"><option value="all" ${filterState.outlineStatus === "all" ? "selected" : ""}>全部大纲状态</option><option value="empty" ${filterState.outlineStatus === "empty" ? "selected" : ""}>尚未规划</option><option value="draft" ${filterState.outlineStatus === "draft" ? "selected" : ""}>草稿</option><option value="ready" ${filterState.outlineStatus === "ready" ? "selected" : ""}>可执行</option><option value="completed" ${filterState.outlineStatus === "completed" ? "selected" : ""}>已完成</option></select></label>
8262
8269
  <label class="setting-filter-field" for="outline-board-foreshadow-filter"><span>按伏笔状态筛选</span><select id="outline-board-foreshadow-filter"><option value="all" ${filterState.foreshadowStatus === "all" ? "selected" : ""}>全部伏笔状态</option><option value="none" ${filterState.foreshadowStatus === "none" ? "selected" : ""}>无关联伏笔</option><option value="unresolved" ${filterState.foreshadowStatus === "unresolved" ? "selected" : ""}>有未回收伏笔</option><option value="resolved" ${filterState.foreshadowStatus === "resolved" ? "selected" : ""}>有已回收伏笔</option><option value="abandoned" ${filterState.foreshadowStatus === "abandoned" ? "selected" : ""}>有已放弃伏笔</option></select></label>
@@ -8266,21 +8273,44 @@ async function renderOutlines(foreshadowPage = moduleListPages.foreshadows) {
8266
8273
  $("#module-content").innerHTML = `${filterToolbar}<div id="outline-board-results"></div><section class="planning-section outline-foreshadow-library"><div class="section-title"><div><span class="eyebrow">伏笔追踪</span><h2>尚未回收与历史伏笔</h2></div></div>${foreshadowHtml}</section>`;
8267
8274
  mountOutlineBoardFilterToggle();
8268
8275
 
8269
- const renderOutlineBoardResults = () => {
8270
- const prepared = prepareOutlineBoard(board, outlineBoardFilters);
8271
- const controlsActive = prepared.filtersActive || prepared.state.sort !== "tree";
8272
- const summary = `<div class="outline-summary"><article><strong>${prepared.filtersActive ? prepared.visibleChapterCount : board.stats.chapterCount}</strong><span>${prepared.filtersActive ? `筛选结果 / 共 ${board.stats.chapterCount} 章` : "全书章节"}</span></article><article><strong>${board.stats.outlinedChapterCount}</strong><span>已有章节大纲</span></article><article class="${board.stats.unresolvedForeshadowCount ? "danger-text" : ""}"><strong>${board.stats.unresolvedForeshadowCount}</strong><span>未回收伏笔</span></article></div>`;
8273
- const boardHtml = prepared.volumes.length
8274
- ? `<div class="outline-board">${prepared.volumes.map((volume) => `<section class="outline-board-volume" data-outline-board-volume="${esc(volume.id)}" aria-labelledby="outline-board-volume-${esc(volume.id)}"><header><div><span class="eyebrow">分卷</span><h3 id="outline-board-volume-${esc(volume.id)}">${esc(volume.title)}</h3></div><span>${volume.chapters.length} 章</span></header>${volume.chapters.length ? `<div class="outline-board-grid">${volume.chapters.map((chapter) => outlineBoardCard(chapter, volume)).join("")}</div>` : '<div class="outline-board-volume-empty"><b>本卷暂无章节</b><span>空分卷会保留在全书看板中。</span></div>'}</section>`).join("")}</div>`
8275
- : emptyModule(board.stats.chapterCount ? "没有符合筛选条件的章节" : board.volumes.length ? "当前分卷还没有章节" : "还没有分卷", board.stats.chapterCount ? "可以调整关键词、状态、分卷或排序条件。" : "先在作品目录创建分卷和章节,再维护每章目标、冲突与转折。");
8276
- $("#outline-board-results").innerHTML = `${summary}<section class="planning-section"><div class="section-title"><div><span class="eyebrow">全书总览</span><h2>章节大纲看板</h2></div><span class="outline-board-result-note">${prepared.visibleChapterCount} / ${board.stats.chapterCount} 章</span></div>${boardHtml}</section>`;
8277
- $("#outline-board-filter-count").textContent = prepared.filtersActive ? `筛选后剩余 ${prepared.visibleChapterCount} 章` : "";
8276
+ const renderOutlineBoardResults = (pageResult) => {
8277
+ const currentFilters = normalizeOutlineBoardState(outlineBoardFilters);
8278
+ const filtersActive = Boolean(currentFilters.query.trim() || currentFilters.volumeId || currentFilters.outlineStatus !== "all" || currentFilters.foreshadowStatus !== "all");
8279
+ const controlsActive = filtersActive || currentFilters.sort !== "tree";
8280
+ const summary = `<div class="outline-summary"><article><strong>${filtersActive ? pageResult.total : pageResult.stats.chapterCount}</strong><span>${filtersActive ? `筛选结果 / 共 ${pageResult.stats.chapterCount} 章` : "全书章节"}</span></article><article><strong>${pageResult.stats.outlinedChapterCount}</strong><span>已有章节大纲</span></article><article class="${pageResult.stats.unresolvedForeshadowCount ? "danger-text" : ""}"><strong>${pageResult.stats.unresolvedForeshadowCount}</strong><span>未回收伏笔</span></article></div>`;
8281
+ const boardHtml = pageResult.volumes.length
8282
+ ? `<div class="outline-board">${pageResult.volumes.map((volume) => `<section class="outline-board-volume" data-outline-board-volume="${esc(volume.id)}" aria-labelledby="outline-board-volume-${esc(volume.id)}"><header><div><span class="eyebrow">分卷</span><h3 id="outline-board-volume-${esc(volume.id)}">${esc(volume.title)}</h3></div><span>${volume.chapters.length === volume.filteredChapterCount ? `${volume.chapters.length} 章` : `本页 ${volume.chapters.length} / ${volume.filteredChapterCount} 章`}</span></header>${volume.chapters.length ? `<div class="outline-board-grid">${volume.chapters.map((chapter) => outlineBoardCard(chapter, volume)).join("")}</div>` : '<div class="outline-board-volume-empty"><b>本卷暂无章节</b><span>空分卷会保留在全书看板中。</span></div>'}</section>`).join("")}</div>`
8283
+ : emptyModule(pageResult.stats.chapterCount ? "没有符合筛选条件的章节" : pageResult.volumeOptions.length ? "当前分卷还没有章节" : "还没有分卷", pageResult.stats.chapterCount ? "可以调整关键词、状态、分卷或排序条件。" : "先在作品目录创建分卷和章节,再维护每章目标、冲突与转折。");
8284
+ const pagination = renderModulePagination(pageResult, "outlinePlans", "章节大纲看板");
8285
+ $("#outline-board-results").innerHTML = `${summary}<section class="planning-section"><div class="section-title"><div><span class="eyebrow">全书总览</span><h2>章节大纲看板</h2></div><span class="outline-board-result-note">本页 ${pageResult.itemCount} / ${pageResult.total} 章</span></div>${boardHtml}${pagination}</section>`;
8286
+ $("#outline-board-filter-count").textContent = filtersActive ? `筛选后共 ${pageResult.total} 章` : "";
8278
8287
  $("#clear-outline-board-filters").disabled = !controlsActive;
8279
- mountModuleCount(prepared.visibleChapterCount + foreshadows.length);
8280
- bindOutlineBoardCards(prepared, workId);
8288
+ mountModuleCount(pageResult.total + foreshadows.length);
8289
+ bindOutlineBoardCards(pageResult, workId);
8290
+ bindModulePagination("outlinePlans", (page) => refreshOutlineBoard(page));
8281
8291
  };
8282
8292
 
8283
- const updateFilters = () => {
8293
+ const refreshOutlineBoard = async (page = 1) => {
8294
+ const pageRequestId = ++outlineBoardRenderRequestId;
8295
+ moduleListPages.outlinePlans = page;
8296
+ $("#outline-board-results")?.setAttribute("aria-busy", "true");
8297
+ $("#outline-board-filter-count").textContent = "正在加载看板…";
8298
+ try {
8299
+ const nextBoard = await moduleApi("outlines", outlineBoardRequestPath(workId, outlineBoardFilters, page, boardPageSize));
8300
+ if (state.work?.id !== workId || generation !== workScopedUiGeneration || pageRequestId !== outlineBoardRenderRequestId || state.module !== "outlines") return;
8301
+ board = nextBoard;
8302
+ moduleListPages.outlinePlans = nextBoard.page;
8303
+ renderOutlineBoardResults(nextBoard);
8304
+ } catch (error) {
8305
+ if (state.work?.id !== workId || generation !== workScopedUiGeneration || pageRequestId !== outlineBoardRenderRequestId || state.module !== "outlines") return;
8306
+ $("#outline-board-filter-count").textContent = "看板加载失败";
8307
+ toast(`读取章节大纲看板失败:${error.message}`, "error");
8308
+ } finally {
8309
+ if (pageRequestId === outlineBoardRenderRequestId) $("#outline-board-results")?.removeAttribute("aria-busy");
8310
+ }
8311
+ };
8312
+
8313
+ const updateFilters = (defer = false) => {
8284
8314
  Object.assign(outlineBoardFilters, normalizeOutlineBoardState({
8285
8315
  query: $("#outline-board-search").value,
8286
8316
  volumeId: $("#outline-board-volume-filter").value,
@@ -8289,10 +8319,16 @@ async function renderOutlines(foreshadowPage = moduleListPages.foreshadows) {
8289
8319
  sort: $("#outline-board-sort").value
8290
8320
  }));
8291
8321
  outlineBoardFiltersPanelOpen = true;
8292
- renderOutlineBoardResults();
8322
+ clearTimeout(outlineBoardSearchTimer);
8323
+ if (defer) {
8324
+ outlineBoardSearchTimer = window.setTimeout(() => { void refreshOutlineBoard(1); }, 250);
8325
+ } else {
8326
+ outlineBoardSearchTimer = null;
8327
+ void refreshOutlineBoard(1);
8328
+ }
8293
8329
  };
8294
- $("#outline-board-search").addEventListener("input", updateFilters);
8295
- ["#outline-board-volume-filter", "#outline-board-status-filter", "#outline-board-foreshadow-filter", "#outline-board-sort"].forEach((selector) => $(selector).addEventListener("change", updateFilters));
8330
+ $("#outline-board-search").addEventListener("input", () => updateFilters(true));
8331
+ ["#outline-board-volume-filter", "#outline-board-status-filter", "#outline-board-foreshadow-filter", "#outline-board-sort"].forEach((selector) => $(selector).addEventListener("change", () => updateFilters(false)));
8296
8332
  $("#clear-outline-board-filters").addEventListener("click", () => {
8297
8333
  Object.assign(outlineBoardFilters, normalizeOutlineBoardState());
8298
8334
  $("#outline-board-search").value = "";
@@ -8301,10 +8337,12 @@ async function renderOutlines(foreshadowPage = moduleListPages.foreshadows) {
8301
8337
  $("#outline-board-foreshadow-filter").value = "all";
8302
8338
  $("#outline-board-sort").value = "tree";
8303
8339
  outlineBoardFiltersPanelOpen = true;
8304
- renderOutlineBoardResults();
8305
8340
  $("#outline-board-search").focus();
8341
+ clearTimeout(outlineBoardSearchTimer);
8342
+ outlineBoardSearchTimer = null;
8343
+ void refreshOutlineBoard(1);
8306
8344
  });
8307
- renderOutlineBoardResults();
8345
+ renderOutlineBoardResults(board);
8308
8346
  bindModuleLayoutToggle(() => renderOutlines(foreshadowPageResult.page));
8309
8347
  bindModulePagination("foreshadows", renderOutlines);
8310
8348
  $("#module-content").querySelectorAll("[data-edit-foreshadow]").forEach((button) => button.addEventListener("click", () => openForeshadowDialog(foreshadows.find((item) => item.id === button.dataset.editForeshadow))));
@@ -10145,7 +10183,7 @@ async function renderBookAiSettings() {
10145
10183
  host.innerHTML = `<section class="config-section">${tokenUsageOverviewMarkup(usage, {
10146
10184
  title: "本书 Token 用量",
10147
10185
  description: `仅统计《${state.work.title}》迄今产生的 AI Token 消耗与缓存命中情况。`
10148
- })}</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 class="checkbox-field config-checkbox-field"><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>设定上下文注入</h2><p>开启后,本书的普通 AI 请求会自动注入锁定设定、组织、种族与相关约束;即使本轮同时使用“@注入上下文设定”,也只会注入一次。</p></div></div><div class="config-inline-save"><label class="checkbox-field config-checkbox-field"><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><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 ai-agent-tools-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)}`;
10186
+ })}</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 class="checkbox-field config-checkbox-field"><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>该阈值按对话历史的独立预算计算,用于显示可选择压缩或忽略的提醒;整次请求达到模型上下文窗口 95% 时仍会强制压缩较早消息,并尽量保留最近八条原文。</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>设定上下文注入</h2><p>开启后,本书的普通 AI 请求会自动注入锁定设定、组织、种族与相关约束;即使本轮同时使用“@注入上下文设定”,也只会注入一次。</p></div></div><div class="config-inline-save"><label class="checkbox-field config-checkbox-field"><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><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 ai-agent-tools-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)}`;
10149
10187
  const agentToolCallLimitInput = host.querySelector("#agent-tool-call-limit");
10150
10188
  agentToolCallLimitInput?.setAttribute("max", String(maximumAgentToolCallLimit));
10151
10189
  const agentToolCallDescription = agentToolCallLimitInput?.closest(".config-section")?.querySelector(".config-section-header p");
@@ -10562,10 +10600,8 @@ function setAiContextDistributionVisible(visible) {
10562
10600
  }
10563
10601
 
10564
10602
  function showAiContextWarning(usage = null) {
10565
- const percent = Math.max(0, Math.round(Number(usage?.conversationUsagePercent) || 0));
10566
- const threshold = Math.max(50, Math.min(90, Number(usage?.compactThreshold) || 85));
10567
- $("#ai-context-warning-title").textContent = percent ? `对话历史已使用 ${percent}% 的独立预算` : "对话历史接近整理阈值";
10568
- $("#ai-context-warning-message").textContent = `已达到 ${threshold}% 的长期记忆整理阈值。现在可整理较早对话或新开对话;若继续发送,系统会先生成带来源的结构化长期记忆。作品正文超限不会触发此操作。`;
10603
+ $("#ai-context-warning-title").textContent = "对话上下文过长";
10604
+ $("#ai-context-warning-message").textContent = "当前对话上下文过长,是否进行压缩?不压缩可能会导致后续请求失败";
10569
10605
  $("#ai-context-warning").classList.remove("hidden");
10570
10606
  }
10571
10607
 
@@ -10573,6 +10609,10 @@ function hideAiContextWarning() {
10573
10609
  $("#ai-context-warning").classList.add("hidden");
10574
10610
  }
10575
10611
 
10612
+ function setAiContextWarningActionsDisabled(disabled) {
10613
+ for (const button of $("#ai-context-warning").querySelectorAll("button")) button.disabled = disabled;
10614
+ }
10615
+
10576
10616
  async function loadAiReferences() {
10577
10617
  const workId = state.work?.id;
10578
10618
  if (!workId) return;
@@ -13342,6 +13382,10 @@ function openModelDialog(providerId, item = null, provider = null) {
13342
13382
  }
13343
13383
 
13344
13384
  async function sendAi() {
13385
+ return sendAiWithOptions();
13386
+ }
13387
+
13388
+ async function sendAiWithOptions({ ignoreContextWarning = false } = {}) {
13345
13389
  if (!state.work) return toast("请先选择作品", "error");
13346
13390
  const composerSnapshot = captureAiPromptComposer();
13347
13391
  const instruction = composerSnapshot.text.trim();
@@ -13414,7 +13458,8 @@ async function sendAi() {
13414
13458
  scope,
13415
13459
  modelId,
13416
13460
  citations,
13417
- conversationId: requestHolder.snapshot.conversationId
13461
+ conversationId: requestHolder.snapshot.conversationId,
13462
+ ...(ignoreContextWarning ? { ignoreContextWarning: true } : {})
13418
13463
  }, createAiIdempotencyKey());
13419
13464
  const request = assertAiRequestCurrent(requestHolder.snapshot);
13420
13465
  if (streamed.action === "warn") return;
@@ -13585,6 +13630,7 @@ async function streamChat(requestHolder, body, idempotencyKey) {
13585
13630
  let conversationTitle = null;
13586
13631
  let persistedUserMessage = null;
13587
13632
  let contextAction = "ready";
13633
+ let warningOnly = false;
13588
13634
  let streamContextCompacted = false;
13589
13635
  let finalAnswerStarted = false;
13590
13636
  const processStartedAt = Date.now();
@@ -13708,6 +13754,11 @@ async function streamChat(requestHolder, body, idempotencyKey) {
13708
13754
  setAiContextMeter(payload.contextUsage);
13709
13755
  if (messageMounted) meta.textContent = "已压缩工具上下文,正在继续生成";
13710
13756
  } else if (eventName === "complete") {
13757
+ if (payload.warningOnly === true) {
13758
+ warningOnly = true;
13759
+ setAiContextMeter(payload.contextUsage);
13760
+ return;
13761
+ }
13711
13762
  mountAssistantMessage();
13712
13763
  persistedMessageId = typeof payload.messageId === "string" ? payload.messageId : null;
13713
13764
  persistedMessageCreatedAt = typeof payload.messageCreatedAt === "string" ? payload.messageCreatedAt : null;
@@ -13739,7 +13790,7 @@ async function streamChat(requestHolder, body, idempotencyKey) {
13739
13790
  assertAiRequestCurrent(requestHolder.snapshot);
13740
13791
  if (streamError) throw streamError;
13741
13792
  assertAiStreamCompleted(streamCompleted);
13742
- return { action: contextAction, content: streamedText, message, metadata: generatedMetadata, messageId: persistedMessageId, createdAt: persistedMessageCreatedAt, conversationTitle, userMessage: persistedUserMessage };
13793
+ return { action: warningOnly ? "warn" : contextAction, content: streamedText, message, metadata: generatedMetadata, messageId: persistedMessageId, createdAt: persistedMessageCreatedAt, conversationTitle, userMessage: persistedUserMessage };
13743
13794
  } catch (error) {
13744
13795
  const streamFailure = error instanceof Error ? error : new Error(String(error ?? "AI 流式调用失败"));
13745
13796
  const interruptionCode = typeof streamFailure.code === "string" ? streamFailure.code.slice(0, 100) : "AI_STREAM_FAILED";
@@ -15665,7 +15716,7 @@ $("#ai-context-compact").addEventListener("click", async () => {
15665
15716
  const modelId = $("#ai-model").value;
15666
15717
  if (!requestScope || !modelId) return toast("请先选择章节和模型", "error");
15667
15718
  const button = $("#ai-context-compact");
15668
- button.disabled = true;
15719
+ setAiContextWarningActionsDisabled(true);
15669
15720
  button.textContent = "压缩中";
15670
15721
  try {
15671
15722
  const conversationId = await ensureAiConversation();
@@ -15674,6 +15725,7 @@ $("#ai-context-compact").addEventListener("click", async () => {
15674
15725
  body: { modelId, scope: requestScope.scope }
15675
15726
  });
15676
15727
  hideAiContextWarning();
15728
+ $("#ai-prompt").focus();
15677
15729
  toast(result.changed ? `已整理 ${result.compactedMessageCount} 条较早消息为长期记忆` : "当前没有需要整理的较早消息");
15678
15730
  setAiContextMeter(result.usage);
15679
15731
  if (result.changed) {
@@ -15687,19 +15739,30 @@ $("#ai-context-compact").addEventListener("click", async () => {
15687
15739
  } catch (error) {
15688
15740
  toast(`上下文压缩失败:${error.message}`, "error");
15689
15741
  } finally {
15690
- button.disabled = false;
15691
- button.textContent = "压缩上下文";
15742
+ setAiContextWarningActionsDisabled(false);
15743
+ button.textContent = "压缩";
15692
15744
  }
15693
15745
  });
15694
15746
  $("#ai-context-new-conversation").addEventListener("click", async () => {
15747
+ setAiContextWarningActionsDisabled(true);
15695
15748
  try {
15696
15749
  await createNewAiConversation();
15697
15750
  hideAiContextWarning();
15698
15751
  } catch (error) {
15699
15752
  toast(error.message, "error");
15753
+ } finally {
15754
+ setAiContextWarningActionsDisabled(false);
15755
+ }
15756
+ });
15757
+ $("#ai-context-dismiss").addEventListener("click", async () => {
15758
+ setAiContextWarningActionsDisabled(true);
15759
+ try {
15760
+ await sendAiWithOptions({ ignoreContextWarning: true });
15761
+ if ($("#ai-context-warning").classList.contains("hidden")) $("#ai-prompt").focus();
15762
+ } finally {
15763
+ setAiContextWarningActionsDisabled(false);
15700
15764
  }
15701
15765
  });
15702
- $("#ai-context-dismiss").addEventListener("click", hideAiContextWarning);
15703
15766
  $("#ai-history-toggle").addEventListener("click", async () => {
15704
15767
  if ($("#ai-history-dialog").open) return setAiHistoryVisible(false);
15705
15768
  try {
@@ -331,8 +331,8 @@
331
331
  <div class="prompt-box">
332
332
  <div id="ai-citations" class="ai-citations hidden" aria-label="已添加的正文引用"></div>
333
333
  <section id="ai-context-warning" class="ai-context-warning hidden" role="status" aria-live="polite">
334
- <div><strong id="ai-context-warning-title">对话历史接近整理阈值</strong><p id="ai-context-warning-message">建议整理为长期记忆或新开对话。</p></div>
335
- <div><button id="ai-context-compact" type="button">整理长期记忆</button><button id="ai-context-new-conversation" type="button">新开对话</button><button id="ai-context-dismiss" type="button">稍后处理</button></div>
334
+ <div><strong id="ai-context-warning-title">对话上下文过长</strong><p id="ai-context-warning-message">当前对话上下文过长,是否进行压缩?不压缩可能会导致后续请求失败</p></div>
335
+ <div><button id="ai-context-compact" type="button">压缩</button><button id="ai-context-dismiss" type="button">忽略</button><button id="ai-context-new-conversation" type="button">新开对话</button></div>
336
336
  </section>
337
337
  <div class="prompt-options">
338
338
  <select id="ai-task" aria-label="任务类型">
@@ -1156,6 +1156,6 @@
1156
1156
  <div id="auth-loading" class="auth-loading" role="status" aria-label="正在载入工作台"></div>
1157
1157
  <script id="vditorIconScript" src="/vendor/vditor/dist/js/icons/ant.js?v=3.11.2"></script>
1158
1158
  <script src="/vendor/vditor/dist/index.min.js?v=3.11.2"></script>
1159
- <script type="module" src="/app.js?v=20260813-reader-volume-mobile-v3"></script>
1159
+ <script type="module" src="/app.js?v=20260813-outline-board-page-v1"></script>
1160
1160
  </body>
1161
1161
  </html>