@cloud411716/fancy-webnovel 1.0.46 → 3.0.0
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/client.js +369 -0
- package/cordis.patch.yml +4 -13
- package/docs/douyin-plugin.md +118 -0
- package/docs/material-library/README.md +404 -0
- package/docs/material-library/import.js +437 -0
- package/docs/material-library/prompt.md +370 -0
- package/docs/material-library/queries.surql +94 -0
- package/docs/material-library/sample.jsonl +14 -0
- package/docs/material-library/schema.surql +46 -0
- package/docs/mcp-profile.example.yml +24 -0
- package/docs/story-graph-design.md +602 -0
- package/docs/story-graph-validation.md +81 -0
- package/docs/workspace-mcp.md +284 -0
- package/index.js +26 -38
- package/lib/atomic-write.js +109 -0
- package/lib/chapter-order.js +100 -0
- package/lib/chinese-num.js +111 -0
- package/lib/confirmation.js +80 -0
- package/lib/db-init.js +123 -0
- package/lib/deployed-state.js +141 -0
- package/lib/direction-labels.js +265 -0
- package/lib/error-codes.js +104 -0
- package/lib/infra.js +594 -0
- package/lib/llm-wiki.js +109 -0
- package/lib/material-db.js +149 -0
- package/lib/path-guard.js +150 -0
- package/lib/projects.js +400 -0
- package/lib/scraper-utils.js +305 -0
- package/lib/surreal-server.js +338 -0
- package/lib/topic-decision.js +860 -0
- package/lib/topic-fields.js +251 -0
- package/lib/topic-schema.js +225 -0
- package/lib/workspace.js +501 -0
- package/package.json +62 -5
- package/plugins/fancy-analyze/analyze-definitions.md +519 -0
- package/plugins/fancy-analyze/command-input.js +65 -0
- package/plugins/fancy-analyze/index.js +2024 -0
- package/plugins/fancy-analyze/ingest-coverage.js +107 -0
- package/plugins/fancy-analyze/schema-analyze.md +627 -0
- package/plugins/fancy-analyze/schema-write.md +178 -0
- package/plugins/fancy-analyze/scripts/append-summary-chapter.js +612 -0
- package/plugins/fancy-analyze/scripts/split_source.js +292 -0
- package/plugins/fancy-analyze/summary-progress.js +495 -0
- package/plugins/fancy-analyze/templates.js +1179 -0
- package/plugins/fancy-bootstrap/index.js +313 -0
- package/plugins/fancy-bootstrap/scripts/init.js +177 -0
- package/plugins/fancy-bootstrap/scripts/path-utils.js +21 -0
- package/plugins/fancy-bootstrap/templates.js +71 -0
- package/plugins/fancy-db/index.js +172 -0
- package/plugins/fancy-douyin/deploy.js +134 -0
- package/plugins/fancy-douyin/index.js +551 -0
- package/plugins/fancy-douyin/prompts/01-analysis-prompt.md +84 -0
- package/plugins/fancy-douyin/scripts/crawl-note.cjs +194 -0
- package/plugins/fancy-douyin/scripts/lib.cjs +197 -0
- package/plugins/fancy-douyin/scripts/scan-account.cjs +128 -0
- package/plugins/fancy-douyin/scripts/start-chrome.cjs +203 -0
- package/plugins/fancy-douyin/state.js +197 -0
- package/plugins/fancy-douyin/templates.js +127 -0
- package/plugins/fancy-export/exporter.js +805 -0
- package/plugins/fancy-export/index.js +63 -0
- package/plugins/fancy-import/import-core.js +1118 -0
- package/plugins/fancy-import/import-driver.js +604 -0
- package/plugins/fancy-import/index.js +738 -0
- package/plugins/fancy-import/prompts/01-import-prompt.md +131 -0
- package/plugins/fancy-import/templates.js +58 -0
- package/plugins/fancy-material/exporter.js +153 -0
- package/plugins/fancy-material/genres.js +256 -0
- package/plugins/fancy-material/index.js +835 -0
- package/plugins/fancy-material/inventory.js +143 -0
- package/plugins/fancy-material/kinds.js +313 -0
- package/plugins/fancy-material/queue.js +55 -0
- package/plugins/fancy-material/scripts/query.js +254 -0
- package/plugins/fancy-material/templates.js +258 -0
- package/plugins/fancy-material/tool-deploy.js +138 -0
- package/plugins/fancy-material/validate.js +149 -0
- package/plugins/fancy-project/index.js +133 -0
- package/plugins/fancy-scan/existing-block.js +100 -0
- package/plugins/fancy-scan/index.js +708 -0
- package/plugins/fancy-scan/prompts/01-analysis-prompt.md +302 -0
- package/plugins/fancy-scan/scripts/append-block.js +725 -0
- package/plugins/fancy-scan/scripts/report-validate.js +824 -0
- package/plugins/fancy-scan/scripts/run-scan.js +667 -0
- package/plugins/fancy-scan/scripts/scrapers/fanqie-rank-scraper.js +923 -0
- package/plugins/fancy-scan/scripts/scrapers/jjwxc-rank-scraper.js +469 -0
- package/plugins/fancy-scan/scripts/scrapers/qimao-rank-scraper.js +629 -0
- package/plugins/fancy-scan/templates/blocks.js +155 -0
- package/plugins/fancy-scan/templates/platforms.js +372 -0
- package/plugins/fancy-scan/templates/report-schema.js +90 -0
- package/plugins/fancy-scan/templates.js +694 -0
- package/plugins/fancy-scan/tool-deploy.js +335 -0
- package/plugins/fancy-scan/wait-turn.js +46 -0
- package/plugins/fancy-story-builder/db/README.md +106 -0
- package/plugins/fancy-story-builder/db/client.js +228 -0
- package/plugins/fancy-story-builder/db/commands.js +145 -0
- package/plugins/fancy-story-builder/db/ids.js +39 -0
- package/plugins/fancy-story-builder/db/import.js +798 -0
- package/plugins/fancy-story-builder/db/project.js +299 -0
- package/plugins/fancy-story-builder/db/query.js +361 -0
- package/plugins/fancy-story-builder/db/schema.js +417 -0
- package/plugins/fancy-story-builder/db/stage-sync.js +238 -0
- package/plugins/fancy-story-builder/deploy-manifest.js +239 -0
- package/plugins/fancy-story-builder/deslop-driver.js +821 -0
- package/plugins/fancy-story-builder/flesh-output.js +168 -0
- package/plugins/fancy-story-builder/index.js +6861 -0
- package/plugins/fancy-story-builder/patch-driver.js +390 -0
- package/plugins/fancy-story-builder/prompts/01-skeleton-prompt.md +563 -0
- package/plugins/fancy-story-builder/prompts/02-flesh-prompt.md +602 -0
- package/plugins/fancy-story-builder/prompts/03-rhythm-prompt.md +539 -0
- package/plugins/fancy-story-builder/prompts/04-writing-prompt.md +225 -0
- package/plugins/fancy-story-builder/prompts/05-deslop-prompt.md +96 -0
- package/plugins/fancy-story-builder/purpose-template.md +83 -0
- package/plugins/fancy-story-builder/references/formulas-rhythm.json +302 -0
- package/plugins/fancy-story-builder/references/formulas-skeleton.json +402 -0
- package/plugins/fancy-story-builder/references/genre-profiles.json +3514 -0
- package/plugins/fancy-story-builder/references/glossary.md +594 -0
- package/plugins/fancy-story-builder/references/index.md +581 -0
- package/plugins/fancy-story-builder/references//345/206/231/344/275/234/346/214/207/345/257/274/00-index.md +174 -0
- package/plugins/fancy-story-builder/references//345/206/231/344/275/234/346/214/207/345/257/274/01-scene.md +150 -0
- package/plugins/fancy-story-builder/references//345/206/231/344/275/234/346/214/207/345/257/274/02-chapter-workflow.md +99 -0
- package/plugins/fancy-story-builder/references//345/206/231/344/275/234/346/214/207/345/257/274/03-opening-chapter.md +104 -0
- package/plugins/fancy-story-builder/references//345/206/231/344/275/234/346/214/207/345/257/274/04-dialogue-mastery.md +274 -0
- package/plugins/fancy-story-builder/references//345/206/231/344/275/234/346/214/207/345/257/274/05-genre-formulas.md +432 -0
- package/plugins/fancy-story-builder/references//345/206/231/344/275/234/346/214/207/345/257/274/06-tone-ensemble.md +259 -0
- package/plugins/fancy-story-builder/references//345/206/231/344/275/234/346/214/207/345/257/274/07-ledger-audit.md +222 -0
- package/plugins/fancy-story-builder/references//345/206/231/344/275/234/346/214/207/345/257/274/08-diagnosis-revision.md +205 -0
- package/plugins/fancy-story-builder/references//345/206/231/344/275/234/346/214/207/345/257/274/09-reading-power.md +135 -0
- package/plugins/fancy-story-builder/references//345/206/231/344/275/234/346/214/207/345/257/274/10-deslop.md +129 -0
- package/plugins/fancy-story-builder/references//350/212/202/345/245/217/346/214/207/345/257/274/00-index.md +98 -0
- package/plugins/fancy-story-builder/references//350/212/202/345/245/217/346/214/207/345/257/274/01-upgrade-rhythm.md +300 -0
- package/plugins/fancy-story-builder/references//350/212/202/345/245/217/346/214/207/345/257/274/02-arc-rhythm.md +168 -0
- package/plugins/fancy-story-builder/references//350/212/202/345/245/217/346/214/207/345/257/274/03-highpoint-hooks.md +189 -0
- package/plugins/fancy-story-builder/references//350/212/202/345/245/217/346/214/207/345/257/274/04-satisfaction.md +226 -0
- package/plugins/fancy-story-builder/references//350/212/202/345/245/217/346/214/207/345/257/274/05-foreshadow-density.md +195 -0
- package/plugins/fancy-story-builder/references//350/212/202/345/245/217/346/214/207/345/257/274/06-chapter-outline.md +226 -0
- package/plugins/fancy-story-builder/references//350/212/202/345/245/217/346/214/207/345/257/274/07-audit.md +181 -0
- package/plugins/fancy-story-builder/references//350/241/200/350/202/211/346/214/207/345/257/274/00-index.md +100 -0
- package/plugins/fancy-story-builder/references//350/241/200/350/202/211/346/214/207/345/257/274/01-character.md +243 -0
- package/plugins/fancy-story-builder/references//350/241/200/350/202/211/346/214/207/345/257/274/02-worldbuilding.md +245 -0
- package/plugins/fancy-story-builder/references//350/241/200/350/202/211/346/214/207/345/257/274/03-relations.md +185 -0
- package/plugins/fancy-story-builder/references//350/241/200/350/202/211/346/214/207/345/257/274/04-emotion-methods.md +286 -0
- package/plugins/fancy-story-builder/references//350/241/200/350/202/211/346/214/207/345/257/274/05-audit.md +187 -0
- package/plugins/fancy-story-builder/references//351/252/250/346/236/266/346/214/207/345/257/274/00-index.md +91 -0
- package/plugins/fancy-story-builder/references//351/252/250/346/236/266/346/214/207/345/257/274/01-positioning.md +209 -0
- package/plugins/fancy-story-builder/references//351/252/250/346/236/266/346/214/207/345/257/274/02-packaging.md +135 -0
- package/plugins/fancy-story-builder/references//351/252/250/346/236/266/346/214/207/345/257/274/03-entities.md +305 -0
- package/plugins/fancy-story-builder/references//351/252/250/346/236/266/346/214/207/345/257/274/04-conflict.md +328 -0
- package/plugins/fancy-story-builder/references//351/252/250/346/236/266/346/214/207/345/257/274/05-quota.md +187 -0
- package/plugins/fancy-story-builder/references//351/252/250/346/236/266/346/214/207/345/257/274/06-audit.md +160 -0
- package/plugins/fancy-story-builder/rhythm-output.js +140 -0
- package/plugins/fancy-story-builder/schema-setting.json +1100 -0
- package/plugins/fancy-story-builder/schema-setting.md +232 -0
- package/plugins/fancy-story-builder/scripts/ai-patterns.js +619 -0
- package/plugins/fancy-story-builder/scripts/brief-validate.js +164 -0
- package/plugins/fancy-story-builder/scripts/check-guide-compliance.js +289 -0
- package/plugins/fancy-story-builder/scripts/content-quality.js +416 -0
- package/plugins/fancy-story-builder/scripts/deslop-validate.js +143 -0
- package/plugins/fancy-story-builder/scripts/error-classes.js +112 -0
- package/plugins/fancy-story-builder/scripts/flesh-validate.js +1312 -0
- package/plugins/fancy-story-builder/scripts/formula-engine.js +112 -0
- package/plugins/fancy-story-builder/scripts/graph-utils.js +1484 -0
- package/plugins/fancy-story-builder/scripts/label-coverage.js +171 -0
- package/plugins/fancy-story-builder/scripts/prompt-drift-check.js +441 -0
- package/plugins/fancy-story-builder/scripts/reading-power.js +298 -0
- package/plugins/fancy-story-builder/scripts/reference-log.js +110 -0
- package/plugins/fancy-story-builder/scripts/rhythm-validate.js +1312 -0
- package/plugins/fancy-story-builder/scripts/schema-pages.js +2668 -0
- package/plugins/fancy-story-builder/scripts/semantic-lint.js +381 -0
- package/plugins/fancy-story-builder/scripts/skeleton-quota.js +145 -0
- package/plugins/fancy-story-builder/scripts/skeleton-validate.js +1973 -0
- package/plugins/fancy-story-builder/scripts/stage-batches.js +1405 -0
- package/plugins/fancy-story-builder/scripts/stage-contract.js +429 -0
- package/plugins/fancy-story-builder/scripts/story-artifacts.js +933 -0
- package/plugins/fancy-story-builder/scripts/upstream-query.js +198 -0
- package/plugins/fancy-story-builder/scripts/v2/baseline.js +112 -0
- package/plugins/fancy-story-builder/scripts/v2/cast.js +517 -0
- package/plugins/fancy-story-builder/scripts/v2/context.js +434 -0
- package/plugins/fancy-story-builder/scripts/v2/contracts.js +493 -0
- package/plugins/fancy-story-builder/scripts/v2/core.js +419 -0
- package/plugins/fancy-story-builder/scripts/v2/engine.js +1068 -0
- package/plugins/fancy-story-builder/scripts/v2/export-markdown.js +794 -0
- package/plugins/fancy-story-builder/scripts/v2/genre.js +195 -0
- package/plugins/fancy-story-builder/scripts/v2/knowledge.js +321 -0
- package/plugins/fancy-story-builder/scripts/v2/macro.js +409 -0
- package/plugins/fancy-story-builder/scripts/v2/manifest.js +538 -0
- package/plugins/fancy-story-builder/scripts/v2/migrate.js +137 -0
- package/plugins/fancy-story-builder/scripts/v2/prompts.js +1335 -0
- package/plugins/fancy-story-builder/scripts/v2/rhythm.js +618 -0
- package/plugins/fancy-story-builder/scripts/v2/scale.js +843 -0
- package/plugins/fancy-story-builder/scripts/v2/snapshot.js +121 -0
- package/plugins/fancy-story-builder/scripts/v2/stages.js +273 -0
- package/plugins/fancy-story-builder/scripts/v2/writing.js +216 -0
- package/plugins/fancy-story-builder/scripts/writing-rules.js +167 -0
- package/plugins/fancy-story-builder/scripts/writing-validate.js +682 -0
- package/plugins/fancy-story-builder/skeleton-output.js +199 -0
- package/plugins/fancy-story-builder/stage-driver.js +1049 -0
- package/plugins/fancy-story-builder/storydb/README.md +271 -0
- package/plugins/fancy-story-builder/storydb/cli.js +458 -0
- package/plugins/fancy-story-builder/storydb/client.js +351 -0
- package/plugins/fancy-story-builder/storydb/compile.js +452 -0
- package/plugins/fancy-story-builder/storydb/context.js +288 -0
- package/plugins/fancy-story-builder/storydb/definitions.js +699 -0
- package/plugins/fancy-story-builder/storydb/driver.js +106 -0
- package/plugins/fancy-story-builder/storydb/dsh-tools.js +313 -0
- package/plugins/fancy-story-builder/storydb/export.js +175 -0
- package/plugins/fancy-story-builder/storydb/ids.js +31 -0
- package/plugins/fancy-story-builder/storydb/impact.js +170 -0
- package/plugins/fancy-story-builder/storydb/import.js +559 -0
- package/plugins/fancy-story-builder/storydb/mcp.js +99 -0
- package/plugins/fancy-story-builder/storydb/prompts.js +952 -0
- package/plugins/fancy-story-builder/storydb/stage-command.js +379 -0
- package/plugins/fancy-story-builder/storydb/stage.js +426 -0
- package/plugins/fancy-story-builder/storydb/store.js +891 -0
- package/plugins/fancy-story-builder/storydb/tools.js +592 -0
- package/plugins/fancy-story-builder/storydb/validation.js +183 -0
- package/plugins/fancy-story-builder/templates/v2/10-scale/scale-template.json +144 -0
- package/plugins/fancy-story-builder/templates/v2/20-macro/emotion-template.json +15 -0
- package/plugins/fancy-story-builder/templates/v2/20-macro/endings-template.json +16 -0
- package/plugins/fancy-story-builder/templates/v2/20-macro/lines-template.json +28 -0
- package/plugins/fancy-story-builder/templates/v2/20-macro/roles-template.json +10 -0
- package/plugins/fancy-story-builder/templates/v2/20-macro/story-template.json +19 -0
- package/plugins/fancy-story-builder/templates/v2/20-macro/volumes-template.json +24 -0
- package/plugins/fancy-story-builder/templates/v2/20-macro/world-template.json +24 -0
- package/plugins/fancy-story-builder/templates/v2/30-cast/characters-template.json +49 -0
- package/plugins/fancy-story-builder/templates/v2/30-cast/climaxes-template.json +14 -0
- package/plugins/fancy-story-builder/templates/v2/30-cast/conflicts-template.json +30 -0
- package/plugins/fancy-story-builder/templates/v2/30-cast/factions-template.json +18 -0
- package/plugins/fancy-story-builder/templates/v2/30-cast/foreshadows-template.json +29 -0
- package/plugins/fancy-story-builder/templates/v2/30-cast/information-template.json +29 -0
- package/plugins/fancy-story-builder/templates/v2/30-cast/items-template.json +13 -0
- package/plugins/fancy-story-builder/templates/v2/30-cast/locations-template.json +12 -0
- package/plugins/fancy-story-builder/templates/v2/30-cast/payoffs-template.json +16 -0
- package/plugins/fancy-story-builder/templates/v2/30-cast/relations-template.json +44 -0
- package/plugins/fancy-story-builder/templates/v2/40-rhythm/chapter-map-template.json +81 -0
- package/plugins/fancy-story-builder/templates/v2/40-rhythm/outline-template.json +162 -0
- package/plugins/fancy-story-builder/templates/v2/50-writing/ledger-template.json +46 -0
- package/plugins/fancy-story-builder/templates/v2/60-deslop/report-template.json +10 -0
- package/plugins/fancy-story-builder/templates//350/212/202/345/245/217//346/227/266/345/272/217/346/230/240/345/260/204/346/250/241/346/235/277.json +427 -0
- package/plugins/fancy-story-builder/templates//350/212/202/345/245/217//347/253/240/350/212/202/347/273/206/347/272/262/346/250/241/346/235/277.json +34 -0
- package/plugins/fancy-story-builder/templates//350/212/202/345/245/217//347/253/240/350/212/202/350/247/204/345/210/222/346/250/241/346/235/277.json +24 -0
- package/plugins/fancy-story-builder/templates//350/212/202/345/245/217//350/212/202/345/245/217/345/217/202/346/225/260/346/250/241/346/235/277.json +27 -0
- package/plugins/fancy-story-builder/templates//350/241/200/350/202/211//344/270/226/347/225/214/350/247/202/350/247/204/345/210/231/346/250/241/346/235/277.json +168 -0
- package/plugins/fancy-story-builder/templates//350/241/200/350/202/211//345/205/263/351/224/256/351/201/223/345/205/267/346/250/241/346/235/277.json +184 -0
- package/plugins/fancy-story-builder/templates//350/241/200/350/202/211//345/205/266/344/273/226/345/256/236/344/275/223/346/250/241/346/235/277.json +62 -0
- package/plugins/fancy-story-builder/templates//350/241/200/350/202/211//345/206/262/347/252/201/346/250/241/346/235/277.json +131 -0
- package/plugins/fancy-story-builder/templates//350/241/200/350/202/211//345/211/247/346/203/205/346/250/241/346/235/277.json +85 -0
- package/plugins/fancy-story-builder/templates//350/241/200/350/202/211//345/212/277/345/212/233/346/250/241/346/235/277.json +103 -0
- package/plugins/fancy-story-builder/templates//350/241/200/350/202/211//345/234/260/347/202/271/346/250/241/346/235/277.json +68 -0
- package/plugins/fancy-story-builder/templates//350/241/200/350/202/211//347/273/223/345/261/200/346/250/241/346/235/277.json +142 -0
- package/plugins/fancy-story-builder/templates//350/241/200/350/202/211//350/247/222/350/211/262/346/250/241/346/235/277.json +292 -0
- package/plugins/fancy-story-builder/templates//351/252/250/346/236/266//345/205/263/347/263/273/346/250/241/346/235/277.json +266 -0
- package/plugins/fancy-story-builder/templates//351/252/250/346/236/266//345/256/236/344/275/223/346/250/241/346/235/277.json +336 -0
- package/plugins/fancy-story-builder/templates//351/252/250/346/236/266//345/261/202/347/272/247/346/250/241/346/235/277.json +65 -0
- package/plugins/fancy-story-builder/templates//351/252/250/346/236/266//346/241/206/346/236/266/346/250/241/346/235/277.json +308 -0
- package/plugins/fancy-story-builder/templates.js +1446 -0
- package/plugins/fancy-story-builder/wiki-references.js +540 -0
- package/plugins/fancy-story-builder/writing-driver.js +1388 -0
- package/plugins/fancy-topic/index.js +1057 -0
- package/plugins/fancy-topic/prompts/01-exploration-prompt.md +115 -0
- package/plugins/fancy-topic/scripts/save-suggestion.js +219 -0
- package/plugins/fancy-topic/scripts/select-topic.js +317 -0
- package/plugins/fancy-topic/templates.js +476 -0
- package/plugins/fancy-topic/tool-deploy.js +200 -0
- package/commands/bootstrap/index.js +0 -164
- package/commands/bootstrap/init-project.js +0 -121
- package/commands/scan/index.js +0 -283
- package/commands/scan/platforms/fanqie.js +0 -146
- package/commands/scan/platforms/jinjiang.js +0 -143
- package/commands/scan/platforms/qidian.js +0 -102
- package/commands/scan/platforms/qimao.js +0 -127
- package/commands/scan/scraper.js +0 -195
- package/infra.js +0 -160
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token-bounded context packs.
|
|
3
|
+
*
|
|
4
|
+
* The LLM should never read a whole stage file. `chapterContext` returns only
|
|
5
|
+
* the chapter, its neighbours, the entities that matter, and the pending work.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { recordLiteral } from './ids.js';
|
|
9
|
+
import { getEntity, requirementsFor } from './store.js';
|
|
10
|
+
|
|
11
|
+
const STORY = 'story:main';
|
|
12
|
+
|
|
13
|
+
function tail(text, chars) {
|
|
14
|
+
const value = String(text || '');
|
|
15
|
+
return value.length <= chars ? value : value.slice(-chars);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function uniqBy(rows, key) {
|
|
19
|
+
const seen = new Set();
|
|
20
|
+
const out = [];
|
|
21
|
+
for (const row of rows) {
|
|
22
|
+
const id = typeof key === 'function' ? key(row) : row[key];
|
|
23
|
+
if (seen.has(id)) continue;
|
|
24
|
+
seen.add(id);
|
|
25
|
+
out.push(row);
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function chapterContext(sdb, displayNo, opts = {}) {
|
|
31
|
+
const chapter = await sdb.one(
|
|
32
|
+
`SELECT * FROM chapter WHERE story = ${STORY} AND display_no = $n LIMIT 1;`,
|
|
33
|
+
{ n: Number(displayNo) },
|
|
34
|
+
);
|
|
35
|
+
if (!chapter) throw new Error('未找到第 ' + displayNo + ' 章');
|
|
36
|
+
const chapterLit = recordLiteral('chapter', chapter.chapter_id);
|
|
37
|
+
|
|
38
|
+
const [outline, castEdges, locationEdges, requirements, foreshadowReq, payoffReq, foreshadowActions, payoffActions, infoActions, climaxEdges, itemEdges, knowledgeEvents] = await Promise.all([
|
|
39
|
+
sdb.one(
|
|
40
|
+
`SELECT * FROM outline WHERE story = ${STORY} AND chapter_id = $id LIMIT 1;`,
|
|
41
|
+
{ id: chapter.chapter_id },
|
|
42
|
+
),
|
|
43
|
+
sdb.rows(
|
|
44
|
+
`SELECT out, role FROM chapter_cast WHERE story = ${STORY} AND in = ${chapterLit};`,
|
|
45
|
+
),
|
|
46
|
+
sdb.rows(
|
|
47
|
+
`SELECT out FROM chapter_location WHERE story = ${STORY} AND in = ${chapterLit};`,
|
|
48
|
+
),
|
|
49
|
+
requirementsFor(sdb, 'chapter:' + chapter.chapter_id),
|
|
50
|
+
sdb.rows(
|
|
51
|
+
`SELECT * FROM requirement WHERE story = ${STORY} AND status = 'pending' AND string::starts_with(subject, 'foreshadow:') ORDER BY due_chapter ASC LIMIT 20;`,
|
|
52
|
+
),
|
|
53
|
+
sdb.rows(
|
|
54
|
+
`SELECT * FROM requirement WHERE story = ${STORY} AND status = 'pending' AND string::starts_with(subject, 'payoff:') ORDER BY due_chapter ASC LIMIT 20;`,
|
|
55
|
+
),
|
|
56
|
+
sdb.rows(
|
|
57
|
+
`SELECT 'foreshadow' AS kind, record::id(out) AS entity_id, action, chapter_no, detail
|
|
58
|
+
FROM foreshadow_action WHERE story = ${STORY} AND in = ${chapterLit};`,
|
|
59
|
+
),
|
|
60
|
+
sdb.rows(
|
|
61
|
+
`SELECT 'payoff' AS kind, record::id(out) AS entity_id, action, chapter_no, detail
|
|
62
|
+
FROM payoff_action WHERE story = ${STORY} AND in = ${chapterLit};`,
|
|
63
|
+
),
|
|
64
|
+
sdb.rows(
|
|
65
|
+
`SELECT 'information' AS kind, record::id(out) AS entity_id, action, chapter_no, detail
|
|
66
|
+
FROM info_action WHERE story = ${STORY} AND in = ${chapterLit};`,
|
|
67
|
+
),
|
|
68
|
+
sdb.rows(
|
|
69
|
+
`SELECT record::id(out) AS entity_id FROM chapter_climax WHERE story = ${STORY} AND in = ${chapterLit};`,
|
|
70
|
+
),
|
|
71
|
+
sdb.rows(
|
|
72
|
+
`SELECT record::id(out) AS entity_id, role FROM chapter_item WHERE story = ${STORY} AND in = ${chapterLit};`,
|
|
73
|
+
),
|
|
74
|
+
sdb.rows(
|
|
75
|
+
`SELECT subject_type, subject_id, character_id, change, coverage, knowledge, how, source_character
|
|
76
|
+
FROM knowledge_event WHERE story = ${STORY} AND chapter = ${chapterLit}
|
|
77
|
+
ORDER BY subject_type, subject_id, character_id;`,
|
|
78
|
+
),
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
const castRecords = castEdges.map((row) => row.out);
|
|
82
|
+
const cast = [];
|
|
83
|
+
for (const row of castEdges) {
|
|
84
|
+
const ref = String(row.out);
|
|
85
|
+
const id = ref.split(':').pop().replace(/[⟨⟩]/g, '');
|
|
86
|
+
const entity = await sdb.one(`SELECT * FROM ${recordLiteral('character', id)};`);
|
|
87
|
+
if (entity) cast.push({ id: entity.entity_id || id, name: entity.name, role: row.role });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const locations = [];
|
|
91
|
+
for (const row of locationEdges) {
|
|
92
|
+
const ref = String(row.out);
|
|
93
|
+
const id = ref.split(':').pop().replace(/[⟨⟩]/g, '');
|
|
94
|
+
const entity = await sdb.one(`SELECT * FROM ${recordLiteral('location', id)};`);
|
|
95
|
+
if (entity) locations.push({ id: entity.entity_id || id, name: entity.name });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const climaxes = [];
|
|
99
|
+
for (const edge of climaxEdges || []) {
|
|
100
|
+
const id = String(edge.entity_id || '').replace(/[⟨⟩]/g, '');
|
|
101
|
+
const entity = await sdb.one(`SELECT * FROM ${recordLiteral('climax', id)};`);
|
|
102
|
+
if (entity) climaxes.push({ id, name: entity.name, type: entity.type, description: entity.description });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const items = [];
|
|
106
|
+
for (const edge of itemEdges || []) {
|
|
107
|
+
const id = String(edge.entity_id || '').replace(/[⟨⟩]/g, '');
|
|
108
|
+
const entity = await sdb.one(`SELECT * FROM ${recordLiteral('item', id)};`);
|
|
109
|
+
if (entity) items.push({ id, name: entity.name, category: entity.category, role: edge.role || '' });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const scenes = outline
|
|
113
|
+
? await sdb.rows(
|
|
114
|
+
`SELECT * FROM scene WHERE story = ${STORY} AND outline_id = $id ORDER BY scene_order;`,
|
|
115
|
+
{ id: chapter.chapter_id },
|
|
116
|
+
)
|
|
117
|
+
: [];
|
|
118
|
+
|
|
119
|
+
const knowledge = [];
|
|
120
|
+
for (const c of cast) {
|
|
121
|
+
const rows = await sdb.rows(
|
|
122
|
+
`SELECT subject_type, subject_id, state FROM knowledge_state
|
|
123
|
+
WHERE story = ${STORY} AND character = ${recordLiteral('character', c.id)}
|
|
124
|
+
ORDER BY subject_type, subject_id;`,
|
|
125
|
+
);
|
|
126
|
+
for (const row of rows) knowledge.push({ character: c.id, ...row });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const prevCount = Math.max(0, Math.min(Number(opts.prev) || 0, 6));
|
|
130
|
+
const tailChars = Math.max(200, Math.min(Number(opts.tailChars) || 600, 2000));
|
|
131
|
+
const previous = [];
|
|
132
|
+
if (prevCount) {
|
|
133
|
+
const rows = await sdb.rows(
|
|
134
|
+
`SELECT chapter_id, display_no, title FROM chapter
|
|
135
|
+
WHERE story = ${STORY} AND display_no < $n ORDER BY display_no DESC LIMIT $k;`,
|
|
136
|
+
{ n: Number(displayNo), k: prevCount },
|
|
137
|
+
);
|
|
138
|
+
rows.reverse();
|
|
139
|
+
for (const row of rows) {
|
|
140
|
+
const [handoff, text] = await Promise.all([
|
|
141
|
+
sdb.one(`SELECT * FROM handoff WHERE story = ${STORY} AND chapter_id = $id LIMIT 1;`, { id: row.chapter_id }),
|
|
142
|
+
sdb.one(`SELECT content FROM chapter_text WHERE story = ${STORY} AND chapter_id = $id LIMIT 1;`, { id: row.chapter_id }),
|
|
143
|
+
]);
|
|
144
|
+
previous.push({
|
|
145
|
+
chapter_id: row.chapter_id,
|
|
146
|
+
display_no: row.display_no,
|
|
147
|
+
title: row.title,
|
|
148
|
+
handoff: handoff || null,
|
|
149
|
+
tail: text ? tail(text.content, tailChars) : '',
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const search = [];
|
|
155
|
+
if (opts.search) {
|
|
156
|
+
const hits = await sdb.rows(
|
|
157
|
+
`SELECT chapter_id, display_no, content, search::score(1) AS score
|
|
158
|
+
FROM chapter_text WHERE content @1@ $q ORDER BY score DESC LIMIT 5;`,
|
|
159
|
+
{ q: String(opts.search) },
|
|
160
|
+
);
|
|
161
|
+
for (const hit of hits) {
|
|
162
|
+
search.push({
|
|
163
|
+
chapter_id: hit.chapter_id,
|
|
164
|
+
display_no: hit.display_no,
|
|
165
|
+
score: hit.score,
|
|
166
|
+
snippet: String(hit.content || '').slice(0, 300),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const foreshadowPending = [];
|
|
172
|
+
for (const req of foreshadowReq) {
|
|
173
|
+
const ref = String(req.subject).split(':');
|
|
174
|
+
if (ref[0] !== 'foreshadow') continue;
|
|
175
|
+
const entity = await sdb.one(`SELECT * FROM ${recordLiteral('foreshadow', ref[1])};`);
|
|
176
|
+
foreshadowPending.push({
|
|
177
|
+
id: ref[1],
|
|
178
|
+
name: entity && entity.name,
|
|
179
|
+
pending: req.kind,
|
|
180
|
+
due_chapter: req.due_chapter,
|
|
181
|
+
hard: Boolean(req.hard),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
const payoffPending = [];
|
|
185
|
+
for (const req of payoffReq) {
|
|
186
|
+
const ref = String(req.subject).split(':');
|
|
187
|
+
if (ref[0] !== 'payoff') continue;
|
|
188
|
+
const entity = await sdb.one(`SELECT * FROM ${recordLiteral('payoff', ref[1])};`);
|
|
189
|
+
payoffPending.push({
|
|
190
|
+
id: ref[1],
|
|
191
|
+
name: entity && entity.name,
|
|
192
|
+
pending: req.kind,
|
|
193
|
+
due_chapter: req.due_chapter,
|
|
194
|
+
hard: Boolean(req.hard),
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
chapter: {
|
|
200
|
+
chapter_id: chapter.chapter_id,
|
|
201
|
+
display_no: chapter.display_no,
|
|
202
|
+
title: chapter.title,
|
|
203
|
+
volume: chapter.volume,
|
|
204
|
+
act: chapter.act,
|
|
205
|
+
pov: chapter.pov,
|
|
206
|
+
time: chapter.time,
|
|
207
|
+
why: chapter.why,
|
|
208
|
+
how: chapter.how,
|
|
209
|
+
emotion: chapter.emotion,
|
|
210
|
+
hook: chapter.hook,
|
|
211
|
+
word_target: chapter.word_target,
|
|
212
|
+
status: chapter.status,
|
|
213
|
+
},
|
|
214
|
+
outline: outline
|
|
215
|
+
? {
|
|
216
|
+
chapter_id: outline.chapter_id,
|
|
217
|
+
must_write: outline.must_write,
|
|
218
|
+
must_not_write: outline.must_not_write,
|
|
219
|
+
continuity: outline.continuity,
|
|
220
|
+
coverage: outline.coverage,
|
|
221
|
+
ending: outline.ending,
|
|
222
|
+
status: outline.status,
|
|
223
|
+
}
|
|
224
|
+
: null,
|
|
225
|
+
scenes,
|
|
226
|
+
cast,
|
|
227
|
+
locations,
|
|
228
|
+
climaxes,
|
|
229
|
+
items,
|
|
230
|
+
knowledge,
|
|
231
|
+
requirements,
|
|
232
|
+
actions: [...(foreshadowActions || []), ...(payoffActions || []), ...(infoActions || [])]
|
|
233
|
+
.sort((a, b) => Number(a.chapter_no) - Number(b.chapter_no)),
|
|
234
|
+
knowledge_events: knowledgeEvents || [],
|
|
235
|
+
foreshadows_due: uniqBy(foreshadowPending, (x) => x.id),
|
|
236
|
+
payoffs_due: uniqBy(payoffPending, (x) => x.id),
|
|
237
|
+
previous,
|
|
238
|
+
search,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export async function entityContext(sdb, kind, id) {
|
|
243
|
+
const entity = await getEntity(sdb, kind, id);
|
|
244
|
+
const requirements = await requirementsFor(sdb, kind + ':' + id);
|
|
245
|
+
const decisions = await sdb.rows(
|
|
246
|
+
`SELECT text, source, reference, reason, status FROM decision
|
|
247
|
+
WHERE story = ${STORY} AND subject = $subject AND status = 'active' ORDER BY created_at DESC;`,
|
|
248
|
+
{ subject: kind + ':' + id },
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
if (kind === 'foreshadow') {
|
|
252
|
+
const actions = await sdb.rows(
|
|
253
|
+
`SELECT in.display_no AS chapter_no, action, detail
|
|
254
|
+
FROM foreshadow_action WHERE story = ${STORY} AND out = ${recordLiteral('foreshadow', id)} ORDER BY chapter_no;`,
|
|
255
|
+
);
|
|
256
|
+
const payoffs = await sdb.rows(
|
|
257
|
+
`SELECT out.entity_id AS payoff, out.name AS name FROM foreshadow_payoff
|
|
258
|
+
WHERE story = ${STORY} AND in = ${recordLiteral('foreshadow', id)};`,
|
|
259
|
+
);
|
|
260
|
+
const knowledge = await sdb.rows(
|
|
261
|
+
`SELECT chapter_no, character_id, change, coverage FROM knowledge_event
|
|
262
|
+
WHERE story = ${STORY} AND subject_type = 'foreshadow' AND subject_id = $id ORDER BY chapter_no;`,
|
|
263
|
+
{ id: String(id) },
|
|
264
|
+
);
|
|
265
|
+
return { entity, requirements, decisions, actions, payoffs, knowledge };
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (kind === 'character') {
|
|
269
|
+
const relations = await sdb.rows(
|
|
270
|
+
`SELECT from_id, to_id, kind, initial_state FROM relation
|
|
271
|
+
WHERE story = ${STORY} AND (from_id = $id OR to_id = $id);`,
|
|
272
|
+
{ id: String(id) },
|
|
273
|
+
);
|
|
274
|
+
const appearances = await sdb.rows(
|
|
275
|
+
`SELECT in.display_no AS chapter_no, in.title AS title, role FROM chapter_cast
|
|
276
|
+
WHERE story = ${STORY} AND out = ${recordLiteral('character', id)} ORDER BY chapter_no;`,
|
|
277
|
+
);
|
|
278
|
+
const knowledge = await sdb.rows(
|
|
279
|
+
`SELECT subject_type, subject_id, state FROM knowledge_state
|
|
280
|
+
WHERE story = ${STORY} AND character = ${recordLiteral('character', id)} ORDER BY subject_type, subject_id;`,
|
|
281
|
+
);
|
|
282
|
+
return { entity, requirements, decisions, relations, appearances, knowledge };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return { entity, requirements, decisions };
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export { tail };
|