@musnows/scriverse 0.9.3 → 0.9.4

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.
@@ -58,16 +58,21 @@ export function normalizeAiContextTokenDistribution(usage) {
58
58
  const systemPromptTokens = tokenCount(distribution.systemPromptTokens);
59
59
  const functionTokens = tokenCount(distribution.functionTokens);
60
60
  const skillsTokens = tokenCount(distribution.skillsTokens);
61
- const contextTokens = Object.keys(distribution).length > 0
61
+ const inputTokens = Object.keys(distribution).length > 0
62
62
  ? tokenCount(distribution.contextTokens)
63
63
  : tokenCount(usage?.inputTokens);
64
- const occupiedTokens = systemPromptTokens + functionTokens + skillsTokens + contextTokens;
64
+ const outputTokens = Math.min(
65
+ tokenCount(distribution.outputTokens ?? usage?.outputReserveTokens),
66
+ Math.max(0, contextWindow - systemPromptTokens - functionTokens - skillsTokens - inputTokens)
67
+ );
68
+ const occupiedTokens = systemPromptTokens + functionTokens + skillsTokens + inputTokens + outputTokens;
65
69
  const leftTokens = Math.max(0, contextWindow - occupiedTokens);
66
70
  const items = [
67
71
  { key: "system-prompt", label: "system prompt", tokens: systemPromptTokens },
68
72
  { key: "function", label: "function", tokens: functionTokens },
69
73
  { key: "skills", label: "skills", tokens: skillsTokens },
70
- { key: "context", label: "context", tokens: contextTokens },
74
+ { key: "input", label: "input", tokens: inputTokens },
75
+ { key: "output", label: "output", tokens: outputTokens },
71
76
  { key: "left", label: "left", tokens: leftTokens }
72
77
  ];
73
78
  return {
@@ -1,5 +1,5 @@
1
1
  import { buildRelationshipGraph, createGalaxyRenderer, normalizeGalaxyFrameRate, normalizeGalaxyMotionMode, renderRelationshipMindMap } from "/relationship-graph.js?v=20260817-relationship-canvas-scale-v1&feature=galaxy-motion-mode-v3&feature=galaxy-edge-label-threshold-v1";
2
- import { collapseExcessBlankLines, formatDateTime, normalizeParagraphSpacing } from "/text-formatting.js?v=20260713-saved-at-seconds";
2
+ import { 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
4
  import { findAiMention, listAiMentionOptions, mergeAiReferenceScope, userMessageMentionNames } from "/ai-mentions.js?v=20260811-user-message-mentions-v1";
5
5
  import {
@@ -32,7 +32,7 @@ import { createStreamTypewriter, createStreamTypewriterSpeedController } from "/
32
32
  import { assertAiStreamCompleted, readAiEventStream } from "/ai-stream-protocol.js?v=20260812-ai-stream-complete-v1";
33
33
  import { buildUsageCalendar, formatCacheHitRate, formatEstimatedCost, formatTokenCount } from "/ai-usage.js?v=20260821-ai-usage-pricing-v1";
34
34
  import { formatAiMessageTime } from "/ai-message-time.js?v=20260801-month-day-time";
35
- import { formatAiContextUsagePercent, formatAiContextUsageTooltip, mergeAiContextUsage, normalizeAiContextTokenDistribution, resolveAiContextUsage } from "/ai-context-meter.js?v=20260819-context-percent-v1";
35
+ import { formatAiContextUsagePercent, formatAiContextUsageTooltip, mergeAiContextUsage, normalizeAiContextTokenDistribution, resolveAiContextUsage } from "/ai-context-meter.js?v=20260827-context-input-output-v1";
36
36
  import { isPhoneClient } from "/phone-client.js?v=20260819-phone-client-v1";
37
37
  import { formatAiToolCallResult } from "/ai-tool-call.js?v=20260801-ai-tool-result-chars-v1";
38
38
  import { copyAiRawMarkdown } from "/ai-message-actions.js?v=20260713-copy-raw-markdown";
@@ -1937,19 +1937,6 @@ function scheduleChapterLineNumbers(delay = 0) {
1937
1937
  }, wait);
1938
1938
  }
1939
1939
 
1940
- function collapseChapterInputBlankLines(input) {
1941
- const value = input.value;
1942
- const normalized = collapseExcessBlankLines(value);
1943
- if (normalized === value) return false;
1944
- const selectionStart = input.selectionStart ?? value.length;
1945
- const selectionEnd = input.selectionEnd ?? selectionStart;
1946
- const nextStart = collapseExcessBlankLines(value.slice(0, selectionStart)).length;
1947
- const nextEnd = collapseExcessBlankLines(value.slice(0, selectionEnd)).length;
1948
- input.value = normalized;
1949
- input.setSelectionRange(nextStart, nextEnd);
1950
- return true;
1951
- }
1952
-
1953
1940
  function lineIndexAtPointer(clientY) {
1954
1941
  const rows = [...$("#chapter-line-numbers-inner").querySelectorAll(".chapter-line-number")];
1955
1942
  if (!rows.length) return 0;
@@ -5635,7 +5622,7 @@ function chapterDraftSnapshot() {
5635
5622
  return {
5636
5623
  chapterId: state.chapter.id,
5637
5624
  title: $("#chapter-title").value.trim(),
5638
- content: normalizeParagraphSpacing($("#chapter-content").value)
5625
+ content: $("#chapter-content").value
5639
5626
  };
5640
5627
  }
5641
5628
 
@@ -5692,11 +5679,6 @@ async function persistChapter({ automatic = false } = {}) {
5692
5679
  if (!automatic) toast("章节标题不能为空", "error");
5693
5680
  return null;
5694
5681
  }
5695
- const input = $("#chapter-content");
5696
- if (input.value !== draft.content) {
5697
- input.value = draft.content;
5698
- scheduleChapterLineNumbers();
5699
- }
5700
5682
  if (sameChapterSnapshot(draft, lastSavedChapterSnapshot)) {
5701
5683
  setSaveState(automatic ? "已自动保存" : collaborationAutoSaveDisabled ? "已保存 · 自动保存已关闭" : "已保存");
5702
5684
  if (!automatic) await loadChapterForeshadowReminders();
@@ -8078,9 +8060,7 @@ async function selectChapter(chapterId, { editMode = false } = {}) {
8078
8060
  $("#chapter-path").textContent = chapterPath;
8079
8061
  $("#chapter-path").title = chapterPath;
8080
8062
  $("#chapter-title").value = state.chapter.title;
8081
- const normalizedContent = normalizeParagraphSpacing(state.chapter.content);
8082
- const spacingChanged = normalizedContent !== state.chapter.content;
8083
- $("#chapter-content").value = normalizedContent;
8063
+ $("#chapter-content").value = state.chapter.content;
8084
8064
  chapterAnnotationCounts = new Map();
8085
8065
  clearChapterLineSelection();
8086
8066
  scheduleChapterLineNumbers();
@@ -8091,7 +8071,6 @@ async function selectChapter(chapterId, { editMode = false } = {}) {
8091
8071
  updateChapterStats();
8092
8072
  if (!canEditProse()) setSaveState("正文只读");
8093
8073
  else if (chapterEditorReadOnly) setSaveState("阅读模式");
8094
- else if (spacingChanged) scheduleChapterAutoSave(120);
8095
8074
  else setSaveState("已保存");
8096
8075
  renderTree();
8097
8076
  replacePageRoute({ view: "editor", workId: state.work.id, chapterId: state.chapter.id });
@@ -12903,9 +12882,11 @@ function renderAiContextDistribution(usage) {
12903
12882
  label.className = "ai-context-distribution-label";
12904
12883
  const title = document.createElement("span");
12905
12884
  title.textContent = item.label;
12906
- if (item.key === "skills" || item.key === "context") {
12885
+ if (item.key === "skills" || item.key === "input" || item.key === "output") {
12907
12886
  const description = document.createElement("small");
12908
- description.textContent = item.key === "skills" ? "待加入" : "用户和 agent 的交互";
12887
+ description.textContent = item.key === "skills"
12888
+ ? "待加入"
12889
+ : item.key === "input" ? "用户和 agent 的交互" : "模型输出预留";
12909
12890
  title.append(" ", description);
12910
12891
  }
12911
12892
  const value = document.createElement("strong");
@@ -12922,6 +12903,7 @@ function renderAiContextDistribution(usage) {
12922
12903
  return row;
12923
12904
  }));
12924
12905
  popover.dataset.hasUsage = String(Boolean(usage));
12906
+ return distribution;
12925
12907
  }
12926
12908
 
12927
12909
  function setAiContextMeter(usage, allowShrink = true) {
@@ -12931,7 +12913,7 @@ function setAiContextMeter(usage, allowShrink = true) {
12931
12913
  latestAiContextUsage = displayUsage;
12932
12914
  const meter = $("#ai-context-meter");
12933
12915
  const value = meter.querySelector("b");
12934
- renderAiContextDistribution(displayUsage);
12916
+ const distribution = renderAiContextDistribution(displayUsage);
12935
12917
  if (!displayUsage) {
12936
12918
  meter.classList.add("is-empty");
12937
12919
  meter.classList.remove("is-warning", "is-danger");
@@ -12942,14 +12924,14 @@ function setAiContextMeter(usage, allowShrink = true) {
12942
12924
  meter.setAttribute("aria-label", tooltip);
12943
12925
  return;
12944
12926
  }
12945
- const percent = Math.max(0, Math.min(100, Number(displayUsage.usagePercent) || 0));
12927
+ const percent = distribution.contextWindow > 0
12928
+ ? Math.min(100, distribution.occupiedTokens / distribution.contextWindow * 100)
12929
+ : 0;
12946
12930
  meter.classList.remove("is-empty");
12947
12931
  meter.classList.toggle("is-warning", percent >= 70 && percent < 90);
12948
12932
  meter.classList.toggle("is-danger", percent >= 90);
12949
12933
  meter.style.setProperty("--context-usage", String(percent));
12950
- value.textContent = Number(displayUsage.inputTokens) > 0
12951
- ? formatAiContextUsagePercent(displayUsage.inputTokens, displayUsage.contextWindow)
12952
- : `${percent}%`;
12934
+ value.textContent = formatAiContextUsagePercent(distribution.occupiedTokens, distribution.contextWindow);
12953
12935
  const tooltip = formatAiContextUsageTooltip(displayUsage);
12954
12936
  meter.dataset.tooltip = tooltip;
12955
12937
  meter.setAttribute("aria-label", `当前上下文用量:${tooltip}`);
@@ -18570,8 +18552,7 @@ $("#appearance-form").addEventListener("submit", (event) => {
18570
18552
  toast(persisted ? "显示设置已保存" : "显示设置已应用,但当前浏览器无法保存偏好", persisted ? "info" : "error");
18571
18553
  });
18572
18554
  $("#chapter-title").addEventListener("input", () => scheduleChapterAutoSave());
18573
- $("#chapter-content").addEventListener("input", (event) => {
18574
- if (!event.isComposing) collapseChapterInputBlankLines(event.currentTarget);
18555
+ $("#chapter-content").addEventListener("input", () => {
18575
18556
  updateChapterStats();
18576
18557
  scheduleChapterAutoSave();
18577
18558
  clearChapterLineSelection();
@@ -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
- <link rel="stylesheet" href="/styles.css?v=20260816-task-scope-volume-collapse-v2&feature=ai-tool-call-copy-feedback-v2&feature=ai-send-control-v3&feature=character-gender-v1&feature=character-filter-state-v1&feature=relationship-canvas-scale-v1&feature=relationship-table-scroll-v1&feature=galaxy-compact-controls-v2&feature=galaxy-motion-mode-v2&feature=chapter-search-replace-v3&feature=task-auto-run-ring-center-v3&feature=character-relationship-delete-v1&feature=ai-assistant-workspace-v2&feature=mobile-module-tab-position-v1&feature=volume-detail-icon-v1&feature=editor-actions-flow-v1&feature=reader-controls-subpanel-v1&feature=reader-focus-ring-v1&feature=ai-message-actions-v1&feature=assistant-responsive-navigation-v2&feature=ai-composer-square-controls-v2&feature=annotation-line-counts-v1&feature=line-number-gutter-fill-v1&feature=ai-relationship-roleplay-v1&feature=ai-model-picker-v1&feature=markdown-word-count-five-digit-v2&feature=ai-stream-character-count-stable-v1&feature=annotation-marker-offset-v1&feature=mobile-ai-entry-hidden-v1&feature=phone-client-entry-v1&feature=ai-stream-idle-timeout-v1&feature=ai-user-message-width-v2&feature=ai-chat-image-attachments-v9&feature=ai-message-image-preview-v1&feature=ai-thinking-scroll-v2&feature=toast-click-dismiss-v3&feature=character-avatar-v6&feature=admin-ai-conversations-v1&feature=ai-usage-pricing-v1&feature=ai-usage-pricing-badge-v2&feature=ai-token-quota-positive-v5&feature=ai-token-usage-details-v1&feature=ai-token-usage-details-centered-v1&feature=ai-stream-connection-seconds-v1&feature=ai-token-usage-estimated-price-v1&feature=record-favorites-v1&feature=entity-detail-favorites-v1&feature=entity-pin-v1&feature=character-persona-summary-v1&feature=ai-roleplay-scene-turn-v1&feature=admin-account-identity-v2&feature=task-detail-failure-orange-v1&feature=character-card-header-alignment-v6&feature=character-card-title-fit-v2&feature=book-import-progress-v1">
13
+ <link rel="stylesheet" href="/styles.css?v=20260816-task-scope-volume-collapse-v2&feature=ai-tool-call-copy-feedback-v2&feature=ai-send-control-v3&feature=character-gender-v1&feature=character-filter-state-v1&feature=relationship-canvas-scale-v1&feature=relationship-table-scroll-v1&feature=galaxy-compact-controls-v2&feature=galaxy-motion-mode-v2&feature=chapter-search-replace-v3&feature=task-auto-run-ring-center-v3&feature=character-relationship-delete-v1&feature=ai-assistant-workspace-v2&feature=mobile-module-tab-position-v1&feature=volume-detail-icon-v1&feature=editor-actions-flow-v1&feature=reader-controls-subpanel-v1&feature=reader-focus-ring-v1&feature=ai-message-actions-v1&feature=assistant-responsive-navigation-v2&feature=ai-composer-square-controls-v2&feature=annotation-line-counts-v1&feature=line-number-gutter-fill-v1&feature=ai-relationship-roleplay-v1&feature=ai-model-picker-v1&feature=markdown-word-count-five-digit-v2&feature=ai-stream-character-count-stable-v1&feature=annotation-marker-offset-v1&feature=mobile-ai-entry-hidden-v1&feature=phone-client-entry-v1&feature=ai-stream-idle-timeout-v1&feature=ai-user-message-width-v2&feature=ai-chat-image-attachments-v9&feature=ai-message-image-preview-v1&feature=ai-thinking-scroll-v2&feature=toast-click-dismiss-v3&feature=character-avatar-v6&feature=admin-ai-conversations-v1&feature=ai-usage-pricing-v1&feature=ai-usage-pricing-badge-v2&feature=ai-token-quota-positive-v5&feature=ai-token-usage-details-v1&feature=ai-token-usage-details-centered-v1&feature=ai-stream-connection-seconds-v1&feature=ai-token-usage-estimated-price-v1&feature=record-favorites-v1&feature=entity-detail-favorites-v1&feature=entity-pin-v1&feature=character-persona-summary-v1&feature=ai-roleplay-scene-turn-v1&feature=admin-account-identity-v2&feature=task-detail-failure-orange-v1&feature=character-card-header-alignment-v6&feature=character-card-title-fit-v2&feature=book-import-progress-v1&feature=editor-toolbar-compact-v2">
14
14
  </head>
15
15
  <body class="auth-pending">
16
16
  <section id="auth-view" class="auth-view hidden" aria-labelledby="auth-title">
@@ -1262,6 +1262,6 @@
1262
1262
  <div id="auth-loading" class="auth-loading" role="status" aria-label="正在载入工作台"></div>
1263
1263
  <script id="vditorIconScript" src="/vendor/vditor/dist/js/icons/ant.js?v=3.11.2"></script>
1264
1264
  <script src="/vendor/vditor/dist/index.min.js?v=3.11.2"></script>
1265
- <script type="module" src="/app.js?v=20260816-extended-thinking-effort-v1&feature=ai-tool-call-copy-feedback-v2&feature=ai-send-control-v2&feature=analysis-task-queue-refresh-v1&feature=character-gender-v1&feature=character-filter-state-v1&feature=relationship-canvas-scale-v1&feature=relationship-table-scroll-v1&feature=ai-session-id-copy-v2&feature=galaxy-motion-mode-v3&feature=galaxy-edge-label-threshold-v1&feature=calculate-time-tool-v2&feature=analysis-task-expired-toast-v1&feature=global-replace-volume-v1&feature=chapter-search-replace-v1&feature=chapter-save-toast-v1&feature=character-relationship-delete-v1&feature=character-relationship-group-v1&feature=analysis-task-stability-delay-v1&feature=ai-assistant-workspace-v2&feature=volume-detail-icon-v1&feature=volume-story-order-v1&feature=reader-manual-chapter-navigation-v1&feature=ai-message-reference-badges-v1&feature=ai-roleplay-message-reference-v1&feature=ai-message-actions-v1&feature=assistant-responsive-navigation-v3&feature=annotation-permissions-v1&feature=annotation-line-counts-v1&feature=ai-relationship-roleplay-v1&feature=ai-roleplay-user-character-visibility-v1&feature=ai-roleplay-story-recall-v1&feature=ai-model-picker-v1&feature=ai-fork-model-unlock-v1&feature=context-percent-format-v1&feature=annotation-precise-locate-v1&feature=markdown-word-count-stable-v1&feature=ai-stream-character-count-stable-v2&feature=ai-process-empty-intermediate-v1&feature=ai-feed-scroll-follow-v1&feature=ai-message-retry-v1&feature=ai-stream-idle-timeout-v2&feature=ai-config-delete-v1&feature=ai-provider-protocol-options-v1&feature=ai-provider-thinking-type-v1&feature=ai-chat-image-attachments-v8&feature=ai-message-image-preview-v1&feature=ai-thinking-scroll-v2&feature=ai-image-conversation-model-lock-v1&feature=toast-click-dismiss-v2&feature=system-restart-dialog-delay-v1&feature=character-avatar-v6&feature=character-death-position-v1&feature=admin-ai-conversations-v1&feature=ai-usage-pricing-v1&feature=ai-usage-pricing-badge-v2&feature=ai-usage-pricing-label-v1&feature=ai-usage-token-breakdown-v1&feature=ai-usage-pricing-cache-v2&feature=ai-usage-pricing-manual-refresh-v1&feature=ai-monthly-token-quota-v1&feature=ai-provider-token-quota-v1&feature=ai-token-quota-positive-v6&feature=ai-model-thinking-label-v1&feature=ai-model-picker-focus-v1&feature=ai-provider-model-import-v1&feature=ai-assistant-brain-icon-v1&feature=ai-token-usage-details-v1&feature=ai-token-usage-details-centered-v1&feature=ai-token-usage-raw-input-v1&feature=ai-stream-connection-seconds-v1&feature=phone-client-entry-v1&feature=ai-usage-pricing-cache-v1&feature=ai-model-thinking-label-v3&feature=ai-roleplay-speaker-label-v1&feature=toast-modal-host-v1&feature=api-key-copy-existing-v1&feature=character-favorite-v1&feature=record-favorites-v1&feature=ai-token-usage-estimated-price-v1&feature=entity-detail-favorites-v1&feature=entity-pin-v1&feature=entity-pin-icon-v1&feature=roleplay-favorite-label-v1&feature=ai-roleplay-knowledge-tools-v1&feature=character-persona-summary-v1&feature=ai-roleplay-scene-turn-v2&feature=admin-account-identity-v2&feature=ai-provider-analysis-timeout-v1&feature=task-detail-failure-orange-v1&feature=book-import-progress-v1&feature=presence-multiple-users-v1"></script>
1265
+ <script type="module" src="/app.js?v=20260816-extended-thinking-effort-v1&feature=ai-tool-call-copy-feedback-v2&feature=ai-send-control-v2&feature=analysis-task-queue-refresh-v1&feature=character-gender-v1&feature=character-filter-state-v1&feature=relationship-canvas-scale-v1&feature=relationship-table-scroll-v1&feature=ai-session-id-copy-v2&feature=galaxy-motion-mode-v3&feature=galaxy-edge-label-threshold-v1&feature=calculate-time-tool-v2&feature=analysis-task-expired-toast-v1&feature=global-replace-volume-v1&feature=chapter-search-replace-v1&feature=chapter-save-toast-v1&feature=character-relationship-delete-v1&feature=character-relationship-group-v1&feature=analysis-task-stability-delay-v1&feature=ai-assistant-workspace-v2&feature=volume-detail-icon-v1&feature=volume-story-order-v1&feature=reader-manual-chapter-navigation-v1&feature=ai-message-reference-badges-v1&feature=ai-roleplay-message-reference-v1&feature=ai-message-actions-v1&feature=assistant-responsive-navigation-v3&feature=annotation-permissions-v1&feature=annotation-line-counts-v1&feature=ai-relationship-roleplay-v1&feature=ai-roleplay-user-character-visibility-v1&feature=ai-roleplay-story-recall-v1&feature=ai-model-picker-v1&feature=ai-fork-model-unlock-v1&feature=context-percent-format-v1&feature=annotation-precise-locate-v1&feature=markdown-word-count-stable-v1&feature=ai-stream-character-count-stable-v2&feature=ai-process-empty-intermediate-v1&feature=ai-feed-scroll-follow-v1&feature=ai-message-retry-v1&feature=ai-stream-idle-timeout-v2&feature=ai-config-delete-v1&feature=ai-provider-protocol-options-v1&feature=ai-provider-thinking-type-v1&feature=ai-chat-image-attachments-v8&feature=ai-message-image-preview-v1&feature=ai-thinking-scroll-v2&feature=ai-image-conversation-model-lock-v1&feature=toast-click-dismiss-v2&feature=system-restart-dialog-delay-v1&feature=character-avatar-v6&feature=character-death-position-v1&feature=admin-ai-conversations-v1&feature=ai-usage-pricing-v1&feature=ai-usage-pricing-badge-v2&feature=ai-usage-pricing-label-v1&feature=ai-usage-token-breakdown-v1&feature=ai-usage-pricing-cache-v2&feature=ai-usage-pricing-manual-refresh-v1&feature=ai-monthly-token-quota-v1&feature=ai-provider-token-quota-v1&feature=ai-token-quota-positive-v6&feature=ai-model-thinking-label-v1&feature=ai-model-picker-focus-v1&feature=ai-provider-model-import-v1&feature=ai-assistant-brain-icon-v1&feature=ai-token-usage-details-v1&feature=ai-token-usage-details-centered-v1&feature=ai-token-usage-raw-input-v1&feature=ai-stream-connection-seconds-v1&feature=phone-client-entry-v1&feature=ai-usage-pricing-cache-v1&feature=ai-model-thinking-label-v3&feature=ai-roleplay-speaker-label-v1&feature=toast-modal-host-v1&feature=api-key-copy-existing-v1&feature=character-favorite-v1&feature=record-favorites-v1&feature=ai-token-usage-estimated-price-v1&feature=entity-detail-favorites-v1&feature=entity-pin-v1&feature=entity-pin-icon-v1&feature=roleplay-favorite-label-v1&feature=ai-roleplay-knowledge-tools-v1&feature=character-persona-summary-v1&feature=ai-roleplay-scene-turn-v2&feature=admin-account-identity-v2&feature=ai-provider-analysis-timeout-v1&feature=task-detail-failure-orange-v1&feature=book-import-progress-v1&feature=presence-multiple-users-v1&feature=ai-context-input-output-v1&feature=editor-blank-lines-preserved-v1"></script>
1266
1266
  </body>
1267
1267
  </html>
@@ -1437,9 +1437,10 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1437
1437
  .editor-view { container-name: editor-workspace; container-type: inline-size; display: grid; grid-template-rows: auto auto minmax(0, 1fr); height: 100%; }
1438
1438
  .editor-toolbar { position: relative; display: grid; grid-row: 1; grid-template-areas: "path path" "title actions"; grid-template-columns: minmax(0, 1fr) auto; align-items: flex-end; column-gap: 20px; row-gap: 6px; padding: 25px 7% 18px; border-bottom: 1px solid var(--line); }
1439
1439
  #chapter-path { grid-area: path; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1440
- .chapter-title { grid-area: title; display: block; width: 100%; min-width: 0; border: 0; border-radius: 0; background: transparent; font-size: 27px; padding: 0; }
1440
+ .chapter-title { grid-area: title; display: block; width: 100%; min-width: 0; border: 0; border-radius: 0; background: transparent; font-size: 25px; padding: 0; }
1441
1441
  .chapter-title:focus { box-shadow: none; border-bottom: 1px solid var(--accent); }
1442
- .editor-actions { grid-area: actions; display: flex; align-items: center; gap: 10px; }
1442
+ .editor-actions { grid-area: actions; display: flex; align-items: center; gap: 8px; }
1443
+ .editor-view .editor-actions > button { min-height: 32px; padding: 6px 10px; font-size: 11px; }
1443
1444
  .chapter-stats { color: var(--muted); font-size: 11px; }
1444
1445
  .chapter-search-panel { position: absolute; z-index: 8; top: calc(100% + 8px); right: 7%; display: grid; width: min(520px, calc(100% - 14%)); gap: 12px; padding: 14px; border: 1px solid var(--line-strong); outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 7px; background: var(--panel); box-shadow: 0 16px 36px rgba(36, 30, 24, .22); }
1445
1446
  .chapter-search-panel-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
@@ -2961,7 +2962,8 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
2961
2962
  .ai-context-distribution-row[data-key="system-prompt"] { --distribution-color: var(--accent); }
2962
2963
  .ai-context-distribution-row[data-key="function"] { --distribution-color: #9a7651; }
2963
2964
  .ai-context-distribution-row[data-key="skills"] { --distribution-color: var(--muted); }
2964
- .ai-context-distribution-row[data-key="context"] { --distribution-color: var(--green); }
2965
+ .ai-context-distribution-row[data-key="input"] { --distribution-color: var(--green); }
2966
+ .ai-context-distribution-row[data-key="output"] { --distribution-color: #718a9f; }
2965
2967
  .ai-context-distribution-row[data-key="left"] { --distribution-color: color-mix(in srgb, var(--muted) 55%, transparent); }
2966
2968
  .ai-send-button { display: grid; flex: 0 0 32px; place-items: center; width: 32px; min-width: 32px; min-height: 32px; height: 32px; padding: 0; border: 0; border-radius: 4px; background: var(--accent); color: #fff; box-shadow: 0 4px 12px rgba(139,61,44,.2); }
2967
2969
  .ai-send-button:hover, .ai-send-button:focus-visible { background: var(--accent-dark); outline: 0; }
@@ -4089,8 +4091,8 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
4089
4091
  .editor-actions { position: static; z-index: auto; right: auto; bottom: auto; left: auto; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; max-width: none; gap: 6px; padding: 0; border: 0; border-radius: 0; background: transparent; box-shadow: none; transform: none; transition: none; }
4090
4092
  .app-shell.left-panel-collapsed .editor-actions { transform: none; pointer-events: auto; }
4091
4093
  .editor-actions .chapter-stats { grid-column: 1 / -1; }
4092
- .editor-actions > button { min-width: 0; min-height: 36px; padding-inline: 8px; font-size: 11px; }
4093
- .chapter-title { font-size: 23px; }
4094
+ .editor-view .editor-actions > button { min-width: 0; min-height: 34px; padding-inline: 6px; font-size: 11px; }
4095
+ .chapter-title { font-size: 21px; }
4094
4096
  .chapter-content { padding: 22px 16px 64px 12px; font-size: max(16px, var(--editor-font-size)); }
4095
4097
  .chapter-line-numbers { width: 32px; font-size: 11px; }
4096
4098
  .chapter-editor-frame { grid-template-columns: 32px minmax(0, 1fr); }
package/dist/store.js CHANGED
@@ -9,7 +9,7 @@ import { accountReference, logger } from "./logger.js";
9
9
  import { paginated, paginationSql } from "./pagination.js";
10
10
  import { currentRequestActor } from "./request-context.js";
11
11
  import { canWriteWorkModule, classifyWorkModulePermissions, emptyWorkModulePermissions, fullWorkModulePermissions, storedWorkModulePermissions } from "./work-permissions.js";
12
- import { countWords, documentShortSearchTerms, escapeSqlLikePattern, id, json, normalizeDocumentSearchText, normalizeParagraphSpacing, now, splitDocumentParagraphs } from "./utils.js";
12
+ import { countWords, documentShortSearchTerms, escapeSqlLikePattern, id, json, normalizeDocumentSearchText, now, splitDocumentParagraphs } from "./utils.js";
13
13
  import { buildWritingCalendar, writingDateKey } from "./writing-progress-time.js";
14
14
  import { resolveMaxAgentToolCallLimit } from "./ai-tool-results.js";
15
15
  import { DEFAULT_AI_STREAM_IDLE_TIMEOUT_SECONDS, normalizeAiStreamIdleTimeoutSeconds } from "./ai-stream-timeout.js";
@@ -2103,7 +2103,7 @@ export class Store {
2103
2103
  const current = this.getChapter(chapterId);
2104
2104
  this.assertExpectedRevision("chapter", chapterId, expectedVersionNo, "章节", Number(current.versionNo));
2105
2105
  const nextTitle = input.title ?? String(current.title);
2106
- const nextContent = input.content === undefined ? String(current.content) : normalizeParagraphSpacing(input.content);
2106
+ const nextContent = input.content === undefined ? String(current.content) : input.content;
2107
2107
  const nextExcluded = input.excludedFromAnalysis ?? Boolean(current.excludedFromAnalysis);
2108
2108
  const nextChapterType = input.chapterType ?? String(current.chapterType);
2109
2109
  const hasTextChange = nextTitle !== current.title || nextContent !== current.content;
@@ -2787,16 +2787,15 @@ export class Store {
2787
2787
  insertChapter(workId, volumeId, title, content, sortOrder, source, sourceRef, chapterType = "正文") {
2788
2788
  const chapterId = id("chapter");
2789
2789
  const timestamp = now();
2790
- const normalizedContent = normalizeParagraphSpacing(content);
2791
2790
  this.db.run(`INSERT INTO chapters (id, work_id, volume_id, title, content, chapter_type, sort_order, word_count, version_no, analysis_status, created_at, updated_at)
2792
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, 'pending', ?, ?)`, chapterId, workId, volumeId, title, normalizedContent, chapterType, sortOrder, countWords(normalizedContent), timestamp, timestamp);
2793
- this.syncChapterParagraphSearch(workId, chapterId, normalizedContent);
2791
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, 'pending', ?, ?)`, chapterId, workId, volumeId, title, content, chapterType, sortOrder, countWords(content), timestamp, timestamp);
2792
+ this.syncChapterParagraphSearch(workId, chapterId, content);
2794
2793
  this.insertChapterVersionRow({
2795
2794
  workId,
2796
2795
  chapterId,
2797
2796
  versionNo: 1,
2798
2797
  title,
2799
- content: normalizedContent,
2798
+ content,
2800
2799
  volumeId,
2801
2800
  sortOrder,
2802
2801
  chapterType,