@kienmatu/inkos 0.1.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/LICENSE +661 -0
- package/dist/book-backup.d.ts +33 -0
- package/dist/book-backup.d.ts.map +1 -0
- package/dist/book-backup.js +74 -0
- package/dist/book-backup.js.map +1 -0
- package/dist/commands/agent.d.ts +3 -0
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +71 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/analytics.d.ts +3 -0
- package/dist/commands/analytics.d.ts.map +1 -0
- package/dist/commands/analytics.js +74 -0
- package/dist/commands/analytics.js.map +1 -0
- package/dist/commands/audit.d.ts +3 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +81 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/auto.d.ts +3 -0
- package/dist/commands/auto.d.ts.map +1 -0
- package/dist/commands/auto.js +136 -0
- package/dist/commands/auto.js.map +1 -0
- package/dist/commands/book.d.ts +3 -0
- package/dist/commands/book.d.ts.map +1 -0
- package/dist/commands/book.js +324 -0
- package/dist/commands/book.js.map +1 -0
- package/dist/commands/chapter.d.ts +3 -0
- package/dist/commands/chapter.d.ts.map +1 -0
- package/dist/commands/chapter.js +103 -0
- package/dist/commands/chapter.js.map +1 -0
- package/dist/commands/compose.d.ts +3 -0
- package/dist/commands/compose.d.ts.map +1 -0
- package/dist/commands/compose.js +46 -0
- package/dist/commands/compose.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +321 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/consolidate.d.ts +3 -0
- package/dist/commands/consolidate.d.ts.map +1 -0
- package/dist/commands/consolidate.js +50 -0
- package/dist/commands/consolidate.js.map +1 -0
- package/dist/commands/daemon.d.ts +4 -0
- package/dist/commands/daemon.d.ts.map +1 -0
- package/dist/commands/daemon.js +118 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/detect.d.ts +3 -0
- package/dist/commands/detect.d.ts.map +1 -0
- package/dist/commands/detect.js +104 -0
- package/dist/commands/detect.js.map +1 -0
- package/dist/commands/doctor.d.ts +8 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +356 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/draft.d.ts +3 -0
- package/dist/commands/draft.d.ts.map +1 -0
- package/dist/commands/draft.js +42 -0
- package/dist/commands/draft.js.map +1 -0
- package/dist/commands/eval.d.ts +3 -0
- package/dist/commands/eval.d.ts.map +1 -0
- package/dist/commands/eval.js +57 -0
- package/dist/commands/eval.js.map +1 -0
- package/dist/commands/export.d.ts +3 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +46 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/fanfic.d.ts +3 -0
- package/dist/commands/fanfic.d.ts.map +1 -0
- package/dist/commands/fanfic.js +177 -0
- package/dist/commands/fanfic.js.map +1 -0
- package/dist/commands/forecast.d.ts +12 -0
- package/dist/commands/forecast.d.ts.map +1 -0
- package/dist/commands/forecast.js +156 -0
- package/dist/commands/forecast.js.map +1 -0
- package/dist/commands/genre.d.ts +11 -0
- package/dist/commands/genre.d.ts.map +1 -0
- package/dist/commands/genre.js +186 -0
- package/dist/commands/genre.js.map +1 -0
- package/dist/commands/import.d.ts +3 -0
- package/dist/commands/import.d.ts.map +1 -0
- package/dist/commands/import.js +110 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +63 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/interact.d.ts +6 -0
- package/dist/commands/interact.d.ts.map +1 -0
- package/dist/commands/interact.js +95 -0
- package/dist/commands/interact.js.map +1 -0
- package/dist/commands/plan.d.ts +3 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/plan.js +50 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/radar.d.ts +3 -0
- package/dist/commands/radar.d.ts.map +1 -0
- package/dist/commands/radar.js +52 -0
- package/dist/commands/radar.js.map +1 -0
- package/dist/commands/review.d.ts +3 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +229 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/revise.d.ts +3 -0
- package/dist/commands/revise.d.ts.map +1 -0
- package/dist/commands/revise.js +91 -0
- package/dist/commands/revise.js.map +1 -0
- package/dist/commands/short-fiction.d.ts +4 -0
- package/dist/commands/short-fiction.d.ts.map +1 -0
- package/dist/commands/short-fiction.js +220 -0
- package/dist/commands/short-fiction.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +123 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/studio.d.ts +21 -0
- package/dist/commands/studio.d.ts.map +1 -0
- package/dist/commands/studio.js +151 -0
- package/dist/commands/studio.js.map +1 -0
- package/dist/commands/style.d.ts +3 -0
- package/dist/commands/style.d.ts.map +1 -0
- package/dist/commands/style.js +95 -0
- package/dist/commands/style.js.map +1 -0
- package/dist/commands/translate.d.ts +3 -0
- package/dist/commands/translate.d.ts.map +1 -0
- package/dist/commands/translate.js +111 -0
- package/dist/commands/translate.js.map +1 -0
- package/dist/commands/tui.d.ts +6 -0
- package/dist/commands/tui.d.ts.map +1 -0
- package/dist/commands/tui.js +14 -0
- package/dist/commands/tui.js.map +1 -0
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +40 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/write.d.ts +3 -0
- package/dist/commands/write.d.ts.map +1 -0
- package/dist/commands/write.js +371 -0
- package/dist/commands/write.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/localization.d.ts +103 -0
- package/dist/localization.d.ts.map +1 -0
- package/dist/localization.js +377 -0
- package/dist/localization.js.map +1 -0
- package/dist/notify-helper.d.ts +17 -0
- package/dist/notify-helper.d.ts.map +1 -0
- package/dist/notify-helper.js +27 -0
- package/dist/notify-helper.js.map +1 -0
- package/dist/program.d.ts +10 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +97 -0
- package/dist/program.js.map +1 -0
- package/dist/progress-text.d.ts +26 -0
- package/dist/progress-text.d.ts.map +1 -0
- package/dist/progress-text.js +35 -0
- package/dist/progress-text.js.map +1 -0
- package/dist/project-bootstrap.d.ts +8 -0
- package/dist/project-bootstrap.d.ts.map +1 -0
- package/dist/project-bootstrap.js +139 -0
- package/dist/project-bootstrap.js.map +1 -0
- package/dist/runtime-requirements.d.ts +24 -0
- package/dist/runtime-requirements.d.ts.map +1 -0
- package/dist/runtime-requirements.js +89 -0
- package/dist/runtime-requirements.js.map +1 -0
- package/dist/tui/__tests__/markdown.test.d.ts +2 -0
- package/dist/tui/__tests__/markdown.test.d.ts.map +1 -0
- package/dist/tui/__tests__/markdown.test.js +58 -0
- package/dist/tui/__tests__/markdown.test.js.map +1 -0
- package/dist/tui/activity-state.d.ts +9 -0
- package/dist/tui/activity-state.d.ts.map +1 -0
- package/dist/tui/activity-state.js +6 -0
- package/dist/tui/activity-state.js.map +1 -0
- package/dist/tui/agent-input.d.ts +118 -0
- package/dist/tui/agent-input.d.ts.map +1 -0
- package/dist/tui/agent-input.js +255 -0
- package/dist/tui/agent-input.js.map +1 -0
- package/dist/tui/ansi.d.ts +40 -0
- package/dist/tui/ansi.d.ts.map +1 -0
- package/dist/tui/ansi.js +62 -0
- package/dist/tui/ansi.js.map +1 -0
- package/dist/tui/app.d.ts +13 -0
- package/dist/tui/app.d.ts.map +1 -0
- package/dist/tui/app.js +109 -0
- package/dist/tui/app.js.map +1 -0
- package/dist/tui/chat-depth.d.ts +9 -0
- package/dist/tui/chat-depth.d.ts.map +1 -0
- package/dist/tui/chat-depth.js +14 -0
- package/dist/tui/chat-depth.js.map +1 -0
- package/dist/tui/chat-draft.d.ts +4 -0
- package/dist/tui/chat-draft.d.ts.map +1 -0
- package/dist/tui/chat-draft.js +28 -0
- package/dist/tui/chat-draft.js.map +1 -0
- package/dist/tui/composer-caret.d.ts +10 -0
- package/dist/tui/composer-caret.d.ts.map +1 -0
- package/dist/tui/composer-caret.js +13 -0
- package/dist/tui/composer-caret.js.map +1 -0
- package/dist/tui/composer-display.d.ts +7 -0
- package/dist/tui/composer-display.d.ts.map +1 -0
- package/dist/tui/composer-display.js +17 -0
- package/dist/tui/composer-display.js.map +1 -0
- package/dist/tui/dashboard-model.d.ts +46 -0
- package/dist/tui/dashboard-model.d.ts.map +1 -0
- package/dist/tui/dashboard-model.js +105 -0
- package/dist/tui/dashboard-model.js.map +1 -0
- package/dist/tui/dashboard.d.ts +38 -0
- package/dist/tui/dashboard.d.ts.map +1 -0
- package/dist/tui/dashboard.js +357 -0
- package/dist/tui/dashboard.js.map +1 -0
- package/dist/tui/effects.d.ts +61 -0
- package/dist/tui/effects.d.ts.map +1 -0
- package/dist/tui/effects.js +451 -0
- package/dist/tui/effects.js.map +1 -0
- package/dist/tui/i18n.d.ts +63 -0
- package/dist/tui/i18n.d.ts.map +1 -0
- package/dist/tui/i18n.js +205 -0
- package/dist/tui/i18n.js.map +1 -0
- package/dist/tui/input-history.d.ts +12 -0
- package/dist/tui/input-history.d.ts.map +1 -0
- package/dist/tui/input-history.js +47 -0
- package/dist/tui/input-history.js.map +1 -0
- package/dist/tui/local-commands.d.ts +12 -0
- package/dist/tui/local-commands.d.ts.map +1 -0
- package/dist/tui/local-commands.js +50 -0
- package/dist/tui/local-commands.js.map +1 -0
- package/dist/tui/markdown.d.ts +2 -0
- package/dist/tui/markdown.d.ts.map +1 -0
- package/dist/tui/markdown.js +60 -0
- package/dist/tui/markdown.js.map +1 -0
- package/dist/tui/session-store.d.ts +2 -0
- package/dist/tui/session-store.d.ts.map +1 -0
- package/dist/tui/session-store.js +2 -0
- package/dist/tui/session-store.js.map +1 -0
- package/dist/tui/setup.d.ts +53 -0
- package/dist/tui/setup.d.ts.map +1 -0
- package/dist/tui/setup.js +313 -0
- package/dist/tui/setup.js.map +1 -0
- package/dist/tui/slash-autocomplete.d.ts +8 -0
- package/dist/tui/slash-autocomplete.d.ts.map +1 -0
- package/dist/tui/slash-autocomplete.js +48 -0
- package/dist/tui/slash-autocomplete.js.map +1 -0
- package/dist/tui/theme.d.ts +28 -0
- package/dist/tui/theme.d.ts.map +1 -0
- package/dist/tui/theme.js +53 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/utils.d.ts +32 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +165 -0
- package/dist/utils.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { StateManager, writeExportArtifact } from "@kienmatu/inkos-core";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { findProjectRoot, resolveBookId, log, logError } from "../utils.js";
|
|
5
|
+
export const exportCommand = new Command("export")
|
|
6
|
+
.description("Export book chapters to a single file")
|
|
7
|
+
.argument("[book-id]", "Book ID (auto-detected if only one book)")
|
|
8
|
+
.option("--format <format>", "Output format (txt, md, epub)", "txt")
|
|
9
|
+
.option("--output <path>", "Output file path")
|
|
10
|
+
.option("--approved-only", "Only export approved chapters")
|
|
11
|
+
.option("--json", "Output JSON metadata")
|
|
12
|
+
.action(async (bookIdArg, opts) => {
|
|
13
|
+
try {
|
|
14
|
+
const root = findProjectRoot();
|
|
15
|
+
const bookId = await resolveBookId(bookIdArg, root);
|
|
16
|
+
const state = new StateManager(root);
|
|
17
|
+
const result = await writeExportArtifact(state, bookId, {
|
|
18
|
+
format: opts.format,
|
|
19
|
+
approvedOnly: Boolean(opts.approvedOnly),
|
|
20
|
+
outputPath: opts.output ?? join(root, `${bookId}_export.${opts.format}`),
|
|
21
|
+
});
|
|
22
|
+
if (opts.json) {
|
|
23
|
+
log(JSON.stringify({
|
|
24
|
+
bookId,
|
|
25
|
+
chaptersExported: result.chaptersExported,
|
|
26
|
+
totalWords: result.totalWords,
|
|
27
|
+
format: result.format,
|
|
28
|
+
outputPath: result.outputPath,
|
|
29
|
+
}, null, 2));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
log(`Exported ${result.chaptersExported} chapters (${result.totalWords} words)`);
|
|
33
|
+
log(`Output: ${result.outputPath}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
if (opts.json) {
|
|
38
|
+
log(JSON.stringify({ error: String(e) }));
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
logError(`Failed to export: ${e}`);
|
|
42
|
+
}
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5E,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,uCAAuC,CAAC;KACpD,QAAQ,CAAC,WAAW,EAAE,0CAA0C,CAAC;KACjE,MAAM,CAAC,mBAAmB,EAAE,+BAA+B,EAAE,KAAK,CAAC;KACnE,MAAM,CAAC,iBAAiB,EAAE,kBAAkB,CAAC;KAC7C,MAAM,CAAC,iBAAiB,EAAE,+BAA+B,CAAC;KAC1D,MAAM,CAAC,QAAQ,EAAE,sBAAsB,CAAC;KACxC,MAAM,CAAC,KAAK,EAAE,SAA6B,EAAE,IAAI,EAAE,EAAE;IACpD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACpD,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;QAErC,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE;YACtD,MAAM,EAAE,IAAI,CAAC,MAA+B;YAC5C,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC;YACxC,UAAU,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,GAAG,MAAM,WAAW,IAAI,CAAC,MAAM,EAAE,CAAC;SACzE,CAAC,CAAC;QAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;gBACjB,MAAM;gBACN,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;gBACzC,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,UAAU,EAAE,MAAM,CAAC,UAAU;aAC9B,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACf,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,YAAY,MAAM,CAAC,gBAAgB,cAAc,MAAM,CAAC,UAAU,SAAS,CAAC,CAAC;YACjF,GAAG,CAAC,WAAW,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC;QACrC,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fanfic.d.ts","sourceRoot":"","sources":["../../src/commands/fanfic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,eAAO,MAAM,aAAa,SACiB,CAAC"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
3
|
+
import { join, resolve, basename } from "node:path";
|
|
4
|
+
import { deriveBookIdFromTitle, normalizePlatformOrOther, PipelineRunner, toWritingLanguage } from "@kienmatu/inkos-core";
|
|
5
|
+
import { loadConfig, buildPipelineConfig, findProjectRoot, resolveBookId, log, logError } from "../utils.js";
|
|
6
|
+
import { formatFanficCanonMissingError, formatFanficInvalidModeError, formatFanficSourceDirEmptyError, formatFanficSourceTooShortError, } from "../localization.js";
|
|
7
|
+
export const fanficCommand = new Command("fanfic")
|
|
8
|
+
.description("Fan fiction writing tools");
|
|
9
|
+
fanficCommand
|
|
10
|
+
.command("init")
|
|
11
|
+
.description("Create a fanfic book from external source material")
|
|
12
|
+
.requiredOption("--title <title>", "Book title")
|
|
13
|
+
.requiredOption("--from <path>", "Source file or directory (novel text, wiki, character docs)")
|
|
14
|
+
.option("--mode <mode>", "Fanfic mode: canon|au|ooc|cp", "canon")
|
|
15
|
+
.option("--genre <genre>", "Genre", "other")
|
|
16
|
+
.option("--platform <platform>", "Target platform", "other")
|
|
17
|
+
.option("--target-chapters <n>", "Target chapter count", "100")
|
|
18
|
+
.option("--chapter-words <n>", "Words per chapter", "3000")
|
|
19
|
+
.option("--lang <language>", "Writing language: zh or en. Defaults from genre.")
|
|
20
|
+
.option("--json", "Output JSON")
|
|
21
|
+
.action(async (opts) => {
|
|
22
|
+
try {
|
|
23
|
+
const config = await loadConfig();
|
|
24
|
+
const root = findProjectRoot();
|
|
25
|
+
const mode = opts.mode;
|
|
26
|
+
if (!["canon", "au", "ooc", "cp"].includes(mode)) {
|
|
27
|
+
throw new Error(formatFanficInvalidModeError(mode));
|
|
28
|
+
}
|
|
29
|
+
// Read source material
|
|
30
|
+
const sourcePath = resolve(opts.from);
|
|
31
|
+
const sourceText = await readSourceMaterial(sourcePath);
|
|
32
|
+
const sourceName = basename(sourcePath);
|
|
33
|
+
if (!sourceText || sourceText.length < 100) {
|
|
34
|
+
throw new Error(formatFanficSourceTooShortError(sourceText.length));
|
|
35
|
+
}
|
|
36
|
+
const bookId = deriveBookIdFromTitle(opts.title) || `book-${Date.now().toString(36)}`;
|
|
37
|
+
const now = new Date().toISOString();
|
|
38
|
+
const book = {
|
|
39
|
+
id: bookId,
|
|
40
|
+
title: opts.title,
|
|
41
|
+
platform: normalizePlatformOrOther(opts.platform),
|
|
42
|
+
genre: opts.genre,
|
|
43
|
+
status: "outlining",
|
|
44
|
+
targetChapters: parseInt(opts.targetChapters, 10),
|
|
45
|
+
chapterWordCount: parseInt(opts.chapterWords, 10),
|
|
46
|
+
language: toWritingLanguage(opts.lang ?? config.language),
|
|
47
|
+
createdAt: now,
|
|
48
|
+
updatedAt: now,
|
|
49
|
+
fanficMode: mode,
|
|
50
|
+
};
|
|
51
|
+
if (!opts.json)
|
|
52
|
+
log(`Creating fanfic "${book.title}" (${mode} mode, ${book.genre})...`);
|
|
53
|
+
if (!opts.json)
|
|
54
|
+
log(` Source: ${sourceName} (${sourceText.length} chars)`);
|
|
55
|
+
const pipeline = new PipelineRunner(buildPipelineConfig(config, root));
|
|
56
|
+
await pipeline.initFanficBook(book, sourceText, sourceName, mode);
|
|
57
|
+
if (opts.json) {
|
|
58
|
+
log(JSON.stringify({
|
|
59
|
+
bookId,
|
|
60
|
+
title: book.title,
|
|
61
|
+
genre: book.genre,
|
|
62
|
+
fanficMode: mode,
|
|
63
|
+
source: sourceName,
|
|
64
|
+
location: `books/${bookId}/`,
|
|
65
|
+
nextStep: `inkos write next ${bookId}`,
|
|
66
|
+
}, null, 2));
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
log(`Fanfic created: ${bookId}`);
|
|
70
|
+
log(` Mode: ${mode}`);
|
|
71
|
+
log(` Location: books/${bookId}/`);
|
|
72
|
+
log(` fanfic_canon.md + foundation generated.`);
|
|
73
|
+
log("");
|
|
74
|
+
log(`Next: inkos write next ${bookId}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
if (opts.json) {
|
|
79
|
+
log(JSON.stringify({ error: String(e) }));
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
logError(`Failed to create fanfic: ${e}`);
|
|
83
|
+
}
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
fanficCommand
|
|
88
|
+
.command("show")
|
|
89
|
+
.description("Display parsed fanfic canon")
|
|
90
|
+
.argument("[book-id]", "Book ID (auto-detected if only one book)")
|
|
91
|
+
.option("--json", "Output JSON")
|
|
92
|
+
.action(async (bookIdArg, opts) => {
|
|
93
|
+
try {
|
|
94
|
+
await loadConfig();
|
|
95
|
+
const root = findProjectRoot();
|
|
96
|
+
const bookId = await resolveBookId(bookIdArg, root);
|
|
97
|
+
const { StateManager } = await import("@kienmatu/inkos-core");
|
|
98
|
+
const state = new StateManager(root);
|
|
99
|
+
const bookDir = state.bookDir(bookId);
|
|
100
|
+
let canon;
|
|
101
|
+
try {
|
|
102
|
+
canon = await readFile(join(bookDir, "story/fanfic_canon.md"), "utf-8");
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
throw new Error(formatFanficCanonMissingError());
|
|
106
|
+
}
|
|
107
|
+
if (opts.json) {
|
|
108
|
+
log(JSON.stringify({ bookId, fanficCanon: canon }, null, 2));
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
log(`Fanfic Canon for "${bookId}":\n`);
|
|
112
|
+
log(canon);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
if (opts.json) {
|
|
117
|
+
log(JSON.stringify({ error: String(e) }));
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
logError(String(e));
|
|
121
|
+
}
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
fanficCommand
|
|
126
|
+
.command("refresh")
|
|
127
|
+
.description("Re-import source material and regenerate fanfic canon")
|
|
128
|
+
.argument("[book-id]", "Book ID (auto-detected if only one book)")
|
|
129
|
+
.requiredOption("--from <path>", "Source file or directory")
|
|
130
|
+
.option("--json", "Output JSON")
|
|
131
|
+
.action(async (bookIdArg, opts) => {
|
|
132
|
+
try {
|
|
133
|
+
const config = await loadConfig();
|
|
134
|
+
const root = findProjectRoot();
|
|
135
|
+
const bookId = await resolveBookId(bookIdArg, root);
|
|
136
|
+
const { StateManager } = await import("@kienmatu/inkos-core");
|
|
137
|
+
const state = new StateManager(root);
|
|
138
|
+
const book = await state.loadBookConfig(bookId);
|
|
139
|
+
const mode = (book.fanficMode ?? "canon");
|
|
140
|
+
const sourcePath = resolve(opts.from);
|
|
141
|
+
const sourceText = await readSourceMaterial(sourcePath);
|
|
142
|
+
const sourceName = basename(sourcePath);
|
|
143
|
+
if (!opts.json)
|
|
144
|
+
log(`Refreshing fanfic canon for "${bookId}" from ${sourceName}...`);
|
|
145
|
+
const pipeline = new PipelineRunner(buildPipelineConfig(config, root));
|
|
146
|
+
await pipeline.importFanficCanon(bookId, sourceText, sourceName, mode);
|
|
147
|
+
if (opts.json) {
|
|
148
|
+
log(JSON.stringify({ bookId, source: sourceName, refreshedAt: new Date().toISOString() }));
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
log(`Canon refreshed from "${sourceName}".`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
if (opts.json) {
|
|
156
|
+
log(JSON.stringify({ error: String(e) }));
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
logError(`Failed to refresh canon: ${e}`);
|
|
160
|
+
}
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
async function readSourceMaterial(sourcePath) {
|
|
165
|
+
const s = await stat(sourcePath);
|
|
166
|
+
if (s.isDirectory()) {
|
|
167
|
+
const files = await readdir(sourcePath);
|
|
168
|
+
const textFiles = files.filter((f) => f.endsWith(".txt") || f.endsWith(".md"));
|
|
169
|
+
if (textFiles.length === 0) {
|
|
170
|
+
throw new Error(formatFanficSourceDirEmptyError(sourcePath));
|
|
171
|
+
}
|
|
172
|
+
const contents = await Promise.all(textFiles.sort().map((f) => readFile(join(sourcePath, f), "utf-8")));
|
|
173
|
+
return contents.join("\n\n---\n\n");
|
|
174
|
+
}
|
|
175
|
+
return readFile(sourcePath, "utf-8");
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=fanfic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fanfic.js","sourceRoot":"","sources":["../../src/commands/fanfic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
export declare const forecastCommand: Command;
|
|
3
|
+
export declare function parseForecastShowArgs(args: ReadonlyArray<string>): {
|
|
4
|
+
readonly bookIdArg?: string;
|
|
5
|
+
readonly forecastId: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function parseForecastSelectArgs(args: ReadonlyArray<string>): {
|
|
8
|
+
readonly bookIdArg?: string;
|
|
9
|
+
readonly forecastId: string;
|
|
10
|
+
readonly branchId: string;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=forecast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forecast.d.ts","sourceRoot":"","sources":["../../src/commands/forecast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC,eAAO,MAAM,eAAe,SAC8D,CAAC;AAqI3F,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG;IAClE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B,CAIA;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG;IACpE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAIA"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { FORECAST_DEFAULT_BRANCHES, FORECAST_DEFAULT_HORIZON, FORECAST_MAX_BRANCHES, FORECAST_MAX_HORIZON, FORECAST_MIN_BRANCHES, FORECAST_MIN_HORIZON, PipelineRunner, createNarrativeForecast, getNarrativeForecast, selectNarrativeBranch, } from "@kienmatu/inkos-core";
|
|
3
|
+
import { buildPipelineConfig, findProjectRoot, loadConfig, log, logError, resolveBookId } from "../utils.js";
|
|
4
|
+
// CLI surface for RFC #342: create / show / select. All three operate only on
|
|
5
|
+
// story/runtime/narrative-forecasts/ artifacts; canonical files stay untouched.
|
|
6
|
+
export const forecastCommand = new Command("forecast")
|
|
7
|
+
.description("Narrative forecast: compare non-canonical future branches before writing");
|
|
8
|
+
forecastCommand
|
|
9
|
+
.command("create")
|
|
10
|
+
.description("Create a narrative forecast (2-5 isolated candidate branches) from the current canon")
|
|
11
|
+
.argument("[book-id]", "Book ID (auto-detected if only one book)")
|
|
12
|
+
.requiredOption("--divergence <text>", "Divergence point to branch on, e.g. \"主角是否接受对手的合作提议\"")
|
|
13
|
+
.option("--branches <n>", `Number of isolated candidate branches (${FORECAST_MIN_BRANCHES}-${FORECAST_MAX_BRANCHES})`, String(FORECAST_DEFAULT_BRANCHES))
|
|
14
|
+
.option("--horizon <n>", `Future chapters each branch covers (${FORECAST_MIN_HORIZON}-${FORECAST_MAX_HORIZON})`, String(FORECAST_DEFAULT_HORIZON))
|
|
15
|
+
.option("--model <model>", "Override the forecast model")
|
|
16
|
+
.option("--llm-base-url <url>", "Override LLM base URL")
|
|
17
|
+
.option("--json", "Output JSON")
|
|
18
|
+
.action(async (bookIdArg, opts) => {
|
|
19
|
+
try {
|
|
20
|
+
const root = findProjectRoot();
|
|
21
|
+
const bookId = await resolveBookId(bookIdArg, root);
|
|
22
|
+
const branchCount = parseBoundedInteger(opts.branches, FORECAST_DEFAULT_BRANCHES, "branches", FORECAST_MIN_BRANCHES, FORECAST_MAX_BRANCHES);
|
|
23
|
+
const horizon = parseBoundedInteger(opts.horizon, FORECAST_DEFAULT_HORIZON, "horizon", FORECAST_MIN_HORIZON, FORECAST_MAX_HORIZON);
|
|
24
|
+
const config = await loadConfig({ projectRoot: root });
|
|
25
|
+
if (opts.llmBaseUrl)
|
|
26
|
+
config.llm.baseUrl = opts.llmBaseUrl;
|
|
27
|
+
if (opts.model)
|
|
28
|
+
config.llm.model = opts.model;
|
|
29
|
+
const pipeline = new PipelineRunner(buildPipelineConfig(config, root, { quiet: Boolean(opts.json) }));
|
|
30
|
+
const result = await createNarrativeForecast({
|
|
31
|
+
projectRoot: root,
|
|
32
|
+
bookId,
|
|
33
|
+
divergence: opts.divergence,
|
|
34
|
+
branchCount,
|
|
35
|
+
horizon,
|
|
36
|
+
runtime: pipeline.createAgentContext("forecast", bookId),
|
|
37
|
+
onProgress: opts.json ? undefined : (message) => log(message),
|
|
38
|
+
});
|
|
39
|
+
if (opts.json) {
|
|
40
|
+
log(JSON.stringify({
|
|
41
|
+
forecast: result.forecast,
|
|
42
|
+
forecastJsonPath: result.forecastJsonPath,
|
|
43
|
+
comparisonPath: result.comparisonPath,
|
|
44
|
+
}, null, 2));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
log(`Forecast created: ${result.forecast.forecastId} (base chapter ${result.forecast.baseChapter})`);
|
|
48
|
+
for (const line of formatBranchLines(result.forecast))
|
|
49
|
+
log(line);
|
|
50
|
+
log(`Comparison: ${result.comparisonPath}`);
|
|
51
|
+
log(`Select a branch with: inkos forecast select ${bookId} ${result.forecast.forecastId} <branch-id>`);
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
failForecastCommand("Forecast create failed", e, opts.json);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
forecastCommand
|
|
58
|
+
.command("show")
|
|
59
|
+
.description("Show a narrative forecast and re-check it against the current canon (marks it stale when canon changed)")
|
|
60
|
+
.argument("<args...>", "[book-id] <forecast-id>")
|
|
61
|
+
.option("--json", "Output JSON")
|
|
62
|
+
.action(async (args, opts) => {
|
|
63
|
+
try {
|
|
64
|
+
const { bookIdArg, forecastId } = parseForecastShowArgs(args);
|
|
65
|
+
const root = findProjectRoot();
|
|
66
|
+
const bookId = await resolveBookId(bookIdArg, root);
|
|
67
|
+
const result = await getNarrativeForecast({ projectRoot: root, bookId, forecastId });
|
|
68
|
+
if (opts.json) {
|
|
69
|
+
log(JSON.stringify({
|
|
70
|
+
forecast: result.forecast,
|
|
71
|
+
stale: result.stale,
|
|
72
|
+
forecastJsonPath: result.forecastJsonPath,
|
|
73
|
+
comparisonPath: result.comparisonPath,
|
|
74
|
+
}, null, 2));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
log(`Forecast ${result.forecast.forecastId} — status: ${result.stale ? "stale" : result.forecast.status}`);
|
|
78
|
+
log(`Divergence: ${result.forecast.divergence}`);
|
|
79
|
+
log(`Base chapter: ${result.forecast.baseChapter}, horizon: ~${result.forecast.horizon} chapters`);
|
|
80
|
+
if (result.stale) {
|
|
81
|
+
log("WARNING: canon changed after this forecast was generated; regenerate before relying on it.");
|
|
82
|
+
}
|
|
83
|
+
for (const line of formatBranchLines(result.forecast))
|
|
84
|
+
log(line);
|
|
85
|
+
log(`Comparison: ${result.comparisonPath}`);
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
failForecastCommand("Forecast show failed", e, opts.json);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
forecastCommand
|
|
92
|
+
.command("select")
|
|
93
|
+
.description("Select a branch: writes only selected-branch-plan.md; canonical files are never modified")
|
|
94
|
+
.argument("<args...>", "[book-id] <forecast-id> <branch-id>")
|
|
95
|
+
.option("--json", "Output JSON")
|
|
96
|
+
.action(async (args, opts) => {
|
|
97
|
+
try {
|
|
98
|
+
const { bookIdArg, forecastId, branchId } = parseForecastSelectArgs(args);
|
|
99
|
+
const root = findProjectRoot();
|
|
100
|
+
const bookId = await resolveBookId(bookIdArg, root);
|
|
101
|
+
const result = await selectNarrativeBranch({ projectRoot: root, bookId, forecastId, branchId });
|
|
102
|
+
if (opts.json) {
|
|
103
|
+
log(JSON.stringify({
|
|
104
|
+
forecastId: result.forecast.forecastId,
|
|
105
|
+
branchId: result.branch.branchId,
|
|
106
|
+
branchTitle: result.branch.title,
|
|
107
|
+
stale: result.stale,
|
|
108
|
+
planPath: result.planPath,
|
|
109
|
+
}, null, 2));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
log(`Selected ${result.branch.branchId} "${result.branch.title}" from ${result.forecast.forecastId}.`);
|
|
113
|
+
if (result.stale) {
|
|
114
|
+
log("WARNING: this forecast is stale; the plan includes a stale warning.");
|
|
115
|
+
}
|
|
116
|
+
log(`Plan: ${result.planPath}`);
|
|
117
|
+
log("Canonical files were not modified. Applying the plan to the outline is a separate, explicit step.");
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
failForecastCommand("Forecast select failed", e, opts.json);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
export function parseForecastShowArgs(args) {
|
|
124
|
+
if (args.length === 1)
|
|
125
|
+
return { forecastId: args[0] };
|
|
126
|
+
if (args.length === 2)
|
|
127
|
+
return { bookIdArg: args[0], forecastId: args[1] };
|
|
128
|
+
throw new Error("Usage: inkos forecast show [book-id] <forecast-id>");
|
|
129
|
+
}
|
|
130
|
+
export function parseForecastSelectArgs(args) {
|
|
131
|
+
if (args.length === 2)
|
|
132
|
+
return { forecastId: args[0], branchId: args[1] };
|
|
133
|
+
if (args.length === 3)
|
|
134
|
+
return { bookIdArg: args[0], forecastId: args[1], branchId: args[2] };
|
|
135
|
+
throw new Error("Usage: inkos forecast select [book-id] <forecast-id> <branch-id>");
|
|
136
|
+
}
|
|
137
|
+
function formatBranchLines(forecast) {
|
|
138
|
+
return forecast.branches.map((branch) => `- ${branch.branchId} "${branch.title}" — intent fit ${branch.intentAlignment.score}/100, ${branch.risks.length} risk(s)`);
|
|
139
|
+
}
|
|
140
|
+
function parseBoundedInteger(value, fallback, name, min, max) {
|
|
141
|
+
const parsed = value ? Number.parseInt(value, 10) : fallback;
|
|
142
|
+
if (!Number.isInteger(parsed) || parsed < min || parsed > max) {
|
|
143
|
+
throw new Error(`${name} must be an integer between ${min} and ${max}.`);
|
|
144
|
+
}
|
|
145
|
+
return parsed;
|
|
146
|
+
}
|
|
147
|
+
function failForecastCommand(prefix, error, json) {
|
|
148
|
+
if (json) {
|
|
149
|
+
log(JSON.stringify({ error: `${prefix}: ${String(error)}` }, null, 2));
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
logError(`${prefix}: ${String(error)}`);
|
|
153
|
+
}
|
|
154
|
+
process.exitCode = 1;
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=forecast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forecast.js","sourceRoot":"","sources":["../../src/commands/forecast.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { type CliLanguage } from "../localization.js";
|
|
3
|
+
export declare function buildGenreTemplate(params: {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly numerical: boolean;
|
|
7
|
+
readonly power: boolean;
|
|
8
|
+
readonly era: boolean;
|
|
9
|
+
}, language?: CliLanguage): string;
|
|
10
|
+
export declare const genreCommand: Command;
|
|
11
|
+
//# sourceMappingURL=genre.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"genre.d.ts","sourceRoot":"","sources":["../../src/commands/genre.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE1E,wBAAgB,kBAAkB,CAChC,MAAM,EAAE;IACN,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;CACvB,EACD,QAAQ,GAAE,WAAkB,GAC3B,MAAM,CA8CR;AAED,eAAO,MAAM,YAAY,SACc,CAAC"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { writeFile, mkdir, readFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { listAvailableGenres, readGenreProfile, getBuiltinGenresDir } from "@kienmatu/inkos-core";
|
|
5
|
+
import { findProjectRoot, log, logError } from "../utils.js";
|
|
6
|
+
import { resolveCliLanguage } from "../localization.js";
|
|
7
|
+
export function buildGenreTemplate(params, language = "zh") {
|
|
8
|
+
if (language === "en") {
|
|
9
|
+
return `---
|
|
10
|
+
name: ${params.name}
|
|
11
|
+
id: ${params.id}
|
|
12
|
+
chapterTypes: ["progression", "setup", "transition", "payoff"]
|
|
13
|
+
fatigueWords: ["shocked", "unbelievable", "incredible"]
|
|
14
|
+
numericalSystem: ${params.numerical}
|
|
15
|
+
powerScaling: ${params.power}
|
|
16
|
+
eraResearch: ${params.era}
|
|
17
|
+
pacingRule: "A clear advance or payoff every 2-3 chapters"
|
|
18
|
+
satisfactionTypes: ["goal achieved", "obstacle overcome", "truth revealed"]
|
|
19
|
+
auditDimensions: [1,2,3,6,7,8,9,10,13,14,15,16,17,18,19]
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Genre Taboos
|
|
23
|
+
|
|
24
|
+
- (add taboos for this genre)
|
|
25
|
+
|
|
26
|
+
## Narrative Guidance
|
|
27
|
+
|
|
28
|
+
(describe the narrative focus and style requirements for this genre)
|
|
29
|
+
`;
|
|
30
|
+
}
|
|
31
|
+
return `---
|
|
32
|
+
name: ${params.name}
|
|
33
|
+
id: ${params.id}
|
|
34
|
+
chapterTypes: ["推进章", "布局章", "过渡章", "回收章"]
|
|
35
|
+
fatigueWords: ["震惊", "不可思议", "难以置信"]
|
|
36
|
+
numericalSystem: ${params.numerical}
|
|
37
|
+
powerScaling: ${params.power}
|
|
38
|
+
eraResearch: ${params.era}
|
|
39
|
+
pacingRule: "每2-3章有一个明确的进展或反馈"
|
|
40
|
+
satisfactionTypes: ["目标达成", "困难克服", "真相揭示"]
|
|
41
|
+
auditDimensions: [1,2,3,6,7,8,9,10,13,14,15,16,17,18,19]
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 题材禁忌
|
|
45
|
+
|
|
46
|
+
- (根据题材添加禁忌)
|
|
47
|
+
|
|
48
|
+
## 叙事指导
|
|
49
|
+
|
|
50
|
+
(根据题材描述叙事重心和风格要求)
|
|
51
|
+
`;
|
|
52
|
+
}
|
|
53
|
+
export const genreCommand = new Command("genre")
|
|
54
|
+
.description("Manage genre profiles");
|
|
55
|
+
genreCommand
|
|
56
|
+
.command("list")
|
|
57
|
+
.description("List all available genre profiles (built-in + project)")
|
|
58
|
+
.action(async () => {
|
|
59
|
+
try {
|
|
60
|
+
const root = findProjectRoot();
|
|
61
|
+
const genres = await listAvailableGenres(root);
|
|
62
|
+
if (genres.length === 0) {
|
|
63
|
+
log("No genre profiles found.");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
log("Available genres:\n");
|
|
67
|
+
for (const g of genres) {
|
|
68
|
+
const tag = g.source === "project" ? "[project]" : "[builtin]";
|
|
69
|
+
log(` ${g.id.padEnd(12)} ${g.name.padEnd(8)} ${tag}`);
|
|
70
|
+
}
|
|
71
|
+
log(`\nTotal: ${genres.length} genre(s)`);
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
logError(`Failed to list genres: ${e}`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
genreCommand
|
|
79
|
+
.command("show")
|
|
80
|
+
.description("Display a genre profile")
|
|
81
|
+
.argument("<id>", "Genre ID (e.g. xuanhuan, urban, horror)")
|
|
82
|
+
.action(async (id) => {
|
|
83
|
+
try {
|
|
84
|
+
const root = findProjectRoot();
|
|
85
|
+
const genres = await listAvailableGenres(root);
|
|
86
|
+
const exactMatch = genres.some(g => g.id === id);
|
|
87
|
+
if (!exactMatch) {
|
|
88
|
+
logError(`Genre "${id}" not found. Available: ${genres.map(g => g.id).join(", ")}`);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
const { profile, body } = await readGenreProfile(root, id);
|
|
92
|
+
log(`Genre: ${profile.name} (${profile.id})\n`);
|
|
93
|
+
log(` Chapter types: ${profile.chapterTypes.join(", ")}`);
|
|
94
|
+
log(` Fatigue words: ${profile.fatigueWords.join(", ")}`);
|
|
95
|
+
log(` Numerical system: ${profile.numericalSystem}`);
|
|
96
|
+
log(` Power scaling: ${profile.powerScaling}`);
|
|
97
|
+
log(` Era research: ${profile.eraResearch}`);
|
|
98
|
+
log(` Pacing rule: ${profile.pacingRule}`);
|
|
99
|
+
log(` Satisfaction types: ${profile.satisfactionTypes.join(", ")}`);
|
|
100
|
+
log(` Audit dimensions: ${profile.auditDimensions.join(", ")}`);
|
|
101
|
+
if (body) {
|
|
102
|
+
log(`\n--- Body ---\n${body}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
logError(`Failed to show genre: ${e}`);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
genreCommand
|
|
111
|
+
.command("create")
|
|
112
|
+
.description("Scaffold a new genre profile in the project genres/ directory")
|
|
113
|
+
.argument("<id>", "Genre ID (e.g. scifi, wuxia, romance)")
|
|
114
|
+
.option("--name <name>", "Genre display name", "")
|
|
115
|
+
.option("--numerical", "Enable numerical system", false)
|
|
116
|
+
.option("--power", "Enable power scaling", false)
|
|
117
|
+
.option("--era", "Enable era research", false)
|
|
118
|
+
.option("--lang <language>", "Template language: zh or en (defaults to INKOS_LOCALE/LANG, then zh)")
|
|
119
|
+
.action(async (id, opts) => {
|
|
120
|
+
try {
|
|
121
|
+
const root = findProjectRoot();
|
|
122
|
+
const genresDir = join(root, "genres");
|
|
123
|
+
const filePath = join(genresDir, `${id}.md`);
|
|
124
|
+
// Check if already exists
|
|
125
|
+
try {
|
|
126
|
+
await readFile(filePath, "utf-8");
|
|
127
|
+
logError(`Genre profile already exists: ${filePath}`);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
catch { /* file doesn't exist, good */ }
|
|
131
|
+
await mkdir(genresDir, { recursive: true });
|
|
132
|
+
const name = opts.name || id;
|
|
133
|
+
const template = buildGenreTemplate({
|
|
134
|
+
id,
|
|
135
|
+
name,
|
|
136
|
+
numerical: opts.numerical,
|
|
137
|
+
power: opts.power,
|
|
138
|
+
era: opts.era,
|
|
139
|
+
}, resolveCliLanguage(opts.lang));
|
|
140
|
+
await writeFile(filePath, template, "utf-8");
|
|
141
|
+
log(`Created genre profile: ${filePath}`);
|
|
142
|
+
log(`Edit the file to customize chapter types, fatigue words, rules, etc.`);
|
|
143
|
+
}
|
|
144
|
+
catch (e) {
|
|
145
|
+
logError(`Failed to create genre: ${e}`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
genreCommand
|
|
150
|
+
.command("copy")
|
|
151
|
+
.description("Copy a built-in genre profile to project for customization")
|
|
152
|
+
.argument("<id>", "Genre ID to copy (e.g. xuanhuan)")
|
|
153
|
+
.action(async (id) => {
|
|
154
|
+
try {
|
|
155
|
+
const root = findProjectRoot();
|
|
156
|
+
const builtinDir = getBuiltinGenresDir();
|
|
157
|
+
const srcPath = join(builtinDir, `${id}.md`);
|
|
158
|
+
const genresDir = join(root, "genres");
|
|
159
|
+
const destPath = join(genresDir, `${id}.md`);
|
|
160
|
+
// Check if project override already exists
|
|
161
|
+
try {
|
|
162
|
+
await readFile(destPath, "utf-8");
|
|
163
|
+
logError(`Project genre profile already exists: ${destPath}`);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
catch { /* doesn't exist, good */ }
|
|
167
|
+
let content;
|
|
168
|
+
try {
|
|
169
|
+
content = await readFile(srcPath, "utf-8");
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
logError(`Built-in genre "${id}" not found. Use 'inkos genre list' to see available genres.`);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
await mkdir(genresDir, { recursive: true });
|
|
177
|
+
await writeFile(destPath, content, "utf-8");
|
|
178
|
+
log(`Copied to: ${destPath}`);
|
|
179
|
+
log(`This project-level copy will override the built-in profile.`);
|
|
180
|
+
}
|
|
181
|
+
catch (e) {
|
|
182
|
+
logError(`Failed to copy genre: ${e}`);
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
//# sourceMappingURL=genre.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"genre.js","sourceRoot":"","sources":["../../src/commands/genre.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAClG,OAAO,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAoB,MAAM,oBAAoB,CAAC;AAE1E,MAAM,UAAU,kBAAkB,CAChC,MAMC,EACD,WAAwB,IAAI;IAE5B,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO;QACH,MAAM,CAAC,IAAI;MACb,MAAM,CAAC,EAAE;;;mBAGI,MAAM,CAAC,SAAS;gBACnB,MAAM,CAAC,KAAK;eACb,MAAM,CAAC,GAAG;;;;;;;;;;;;;CAaxB,CAAC;IACA,CAAC;IAED,OAAO;QACD,MAAM,CAAC,IAAI;MACb,MAAM,CAAC,EAAE;;;mBAGI,MAAM,CAAC,SAAS;gBACnB,MAAM,CAAC,KAAK;eACb,MAAM,CAAC,GAAG;;;;;;;;;;;;;CAaxB,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,uBAAuB,CAAC,CAAC;AAExC,YAAY;KACT,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,wDAAwD,CAAC;KACrE,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC;QAE/C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,GAAG,CAAC,0BAA0B,CAAC,CAAC;YAChC,OAAO;QACT,CAAC;QAED,GAAG,CAAC,qBAAqB,CAAC,CAAC;QAC3B,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC;YAC/D,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;QACzD,CAAC;QACD,GAAG,CAAC,YAAY,MAAM,CAAC,MAAM,WAAW,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,QAAQ,CAAC,0BAA0B,CAAC,EAAE,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,YAAY;KACT,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,yBAAyB,CAAC;KACtC,QAAQ,CAAC,MAAM,EAAE,yCAAyC,CAAC;KAC3D,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,EAAE;IAC3B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC;QAC/C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACjD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,QAAQ,CAAC,UAAU,EAAE,2BAA2B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACpF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAE3D,GAAG,CAAC,UAAU,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC;QAChD,GAAG,CAAC,yBAAyB,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChE,GAAG,CAAC,yBAAyB,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChE,GAAG,CAAC,yBAAyB,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;QACxD,GAAG,CAAC,yBAAyB,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;QACrD,GAAG,CAAC,yBAAyB,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;QACpD,GAAG,CAAC,yBAAyB,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;QACnD,GAAG,CAAC,yBAAyB,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrE,GAAG,CAAC,yBAAyB,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEnE,IAAI,IAAI,EAAE,CAAC;YACT,GAAG,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,QAAQ,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,YAAY;KACT,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,+DAA+D,CAAC;KAC5E,QAAQ,CAAC,MAAM,EAAE,uCAAuC,CAAC;KACzD,MAAM,CAAC,eAAe,EAAE,oBAAoB,EAAE,EAAE,CAAC;KACjD,MAAM,CAAC,aAAa,EAAE,yBAAyB,EAAE,KAAK,CAAC;KACvD,MAAM,CAAC,SAAS,EAAE,sBAAsB,EAAE,KAAK,CAAC;KAChD,MAAM,CAAC,OAAO,EAAE,qBAAqB,EAAE,KAAK,CAAC;KAC7C,MAAM,CAAC,mBAAmB,EAAE,sEAAsE,CAAC;KACnG,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,IAAI,EAAE,EAAE;IACjC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAE7C,0BAA0B;QAC1B,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAClC,QAAQ,CAAC,iCAAiC,QAAQ,EAAE,CAAC,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC,CAAC,8BAA8B,CAAC,CAAC;QAE1C,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE5C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,kBAAkB,CACjC;YACE,EAAE;YACF,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,EACD,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAC9B,CAAC;QAEF,MAAM,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC7C,GAAG,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC;QAC1C,GAAG,CAAC,sEAAsE,CAAC,CAAC;IAC9E,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,QAAQ,CAAC,2BAA2B,CAAC,EAAE,CAAC,CAAC;QACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,YAAY;KACT,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,4DAA4D,CAAC;KACzE,QAAQ,CAAC,MAAM,EAAE,kCAAkC,CAAC;KACpD,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,EAAE;IAC3B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;QAC/B,MAAM,UAAU,GAAG,mBAAmB,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAE7C,2CAA2C;QAC3C,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAClC,QAAQ,CAAC,yCAAyC,QAAQ,EAAE,CAAC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC,CAAC,yBAAyB,CAAC,CAAC;QAErC,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,CAAC,mBAAmB,EAAE,8DAA8D,CAAC,CAAC;YAC9F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChB,OAAO;QACT,CAAC;QAED,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC5C,GAAG,CAAC,cAAc,QAAQ,EAAE,CAAC,CAAC;QAC9B,GAAG,CAAC,6DAA6D,CAAC,CAAC;IACrE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,QAAQ,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|