@actalk/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.
Files changed (49) hide show
  1. package/dist/commands/book.d.ts +3 -0
  2. package/dist/commands/book.d.ts.map +1 -0
  3. package/dist/commands/book.js +77 -0
  4. package/dist/commands/book.js.map +1 -0
  5. package/dist/commands/config.d.ts +3 -0
  6. package/dist/commands/config.d.ts.map +1 -0
  7. package/dist/commands/config.js +57 -0
  8. package/dist/commands/config.js.map +1 -0
  9. package/dist/commands/daemon.d.ts +4 -0
  10. package/dist/commands/daemon.d.ts.map +1 -0
  11. package/dist/commands/daemon.js +93 -0
  12. package/dist/commands/daemon.js.map +1 -0
  13. package/dist/commands/doctor.d.ts +3 -0
  14. package/dist/commands/doctor.d.ts.map +1 -0
  15. package/dist/commands/doctor.js +76 -0
  16. package/dist/commands/doctor.js.map +1 -0
  17. package/dist/commands/export.d.ts +3 -0
  18. package/dist/commands/export.d.ts.map +1 -0
  19. package/dist/commands/export.js +56 -0
  20. package/dist/commands/export.js.map +1 -0
  21. package/dist/commands/init.d.ts +3 -0
  22. package/dist/commands/init.d.ts.map +1 -0
  23. package/dist/commands/init.js +54 -0
  24. package/dist/commands/init.js.map +1 -0
  25. package/dist/commands/radar.d.ts +3 -0
  26. package/dist/commands/radar.d.ts.map +1 -0
  27. package/dist/commands/radar.js +45 -0
  28. package/dist/commands/radar.js.map +1 -0
  29. package/dist/commands/review.d.ts +3 -0
  30. package/dist/commands/review.d.ts.map +1 -0
  31. package/dist/commands/review.js +123 -0
  32. package/dist/commands/review.js.map +1 -0
  33. package/dist/commands/status.d.ts +3 -0
  34. package/dist/commands/status.d.ts.map +1 -0
  35. package/dist/commands/status.js +37 -0
  36. package/dist/commands/status.js.map +1 -0
  37. package/dist/commands/write.d.ts +3 -0
  38. package/dist/commands/write.d.ts.map +1 -0
  39. package/dist/commands/write.js +113 -0
  40. package/dist/commands/write.js.map +1 -0
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +30 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/utils.d.ts +7 -0
  46. package/dist/utils.d.ts.map +1 -0
  47. package/dist/utils.js +30 -0
  48. package/dist/utils.js.map +1 -0
  49. package/package.json +35 -0
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare const bookCommand: Command;
3
+ //# sourceMappingURL=book.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"book.d.ts","sourceRoot":"","sources":["../../src/commands/book.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,eAAO,MAAM,WAAW,SACM,CAAC"}
@@ -0,0 +1,77 @@
1
+ import { Command } from "commander";
2
+ import { PipelineRunner, StateManager } from "@actalk/inkos-core";
3
+ import { loadConfig, createClient, findProjectRoot, log, logError } from "../utils.js";
4
+ export const bookCommand = new Command("book")
5
+ .description("Manage books");
6
+ bookCommand
7
+ .command("create")
8
+ .description("Create a new book with AI-generated foundation")
9
+ .requiredOption("--title <title>", "Book title")
10
+ .option("--genre <genre>", "Genre", "xuanhuan")
11
+ .option("--platform <platform>", "Target platform", "tomato")
12
+ .option("--target-chapters <n>", "Target chapter count", "200")
13
+ .option("--chapter-words <n>", "Words per chapter", "3000")
14
+ .action(async (opts) => {
15
+ try {
16
+ const config = await loadConfig();
17
+ const client = createClient(config);
18
+ const root = findProjectRoot();
19
+ const bookId = opts.title
20
+ .toLowerCase()
21
+ .replace(/[^a-z0-9\u4e00-\u9fff]/g, "-")
22
+ .replace(/-+/g, "-")
23
+ .slice(0, 30);
24
+ const now = new Date().toISOString();
25
+ const book = {
26
+ id: bookId,
27
+ title: opts.title,
28
+ platform: opts.platform,
29
+ genre: opts.genre,
30
+ status: "outlining",
31
+ targetChapters: parseInt(opts.targetChapters, 10),
32
+ chapterWordCount: parseInt(opts.chapterWords, 10),
33
+ createdAt: now,
34
+ updatedAt: now,
35
+ };
36
+ log(`Creating book "${book.title}" (${book.genre} / ${book.platform})...`);
37
+ const pipeline = new PipelineRunner({
38
+ client,
39
+ model: config.llm.model,
40
+ projectRoot: root,
41
+ });
42
+ await pipeline.initBook(book);
43
+ log(`Book created: ${bookId}`);
44
+ log(` Location: books/${bookId}/`);
45
+ log(` Story bible, outline, style guide generated.`);
46
+ log("");
47
+ log(`Next: inkos write next ${bookId}`);
48
+ }
49
+ catch (e) {
50
+ logError(`Failed to create book: ${e}`);
51
+ process.exit(1);
52
+ }
53
+ });
54
+ bookCommand
55
+ .command("list")
56
+ .description("List all books")
57
+ .action(async () => {
58
+ try {
59
+ const root = findProjectRoot();
60
+ const state = new StateManager(root);
61
+ const bookIds = await state.listBooks();
62
+ if (bookIds.length === 0) {
63
+ log("No books found. Create one with: inkos book create --title '...'");
64
+ return;
65
+ }
66
+ for (const id of bookIds) {
67
+ const book = await state.loadBookConfig(id);
68
+ const nextChapter = await state.getNextChapterNumber(id);
69
+ log(` ${id} | ${book.title} | ${book.genre}/${book.platform} | ${book.status} | chapters: ${nextChapter - 1}`);
70
+ }
71
+ }
72
+ catch (e) {
73
+ logError(`Failed to list books: ${e}`);
74
+ process.exit(1);
75
+ }
76
+ });
77
+ //# sourceMappingURL=book.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"book.js","sourceRoot":"","sources":["../../src/commands/book.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare const configCommand: Command;
3
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,aAAa,SACoB,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { Command } from "commander";
2
+ import { readFile, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { findProjectRoot, log, logError } from "../utils.js";
5
+ export const configCommand = new Command("config")
6
+ .description("Manage project configuration");
7
+ configCommand
8
+ .command("set")
9
+ .description("Set a configuration value")
10
+ .argument("<key>", "Config key (e.g., llm.apiKey)")
11
+ .argument("<value>", "Config value")
12
+ .action(async (key, value) => {
13
+ const root = findProjectRoot();
14
+ const configPath = join(root, "inkos.json");
15
+ try {
16
+ const raw = await readFile(configPath, "utf-8");
17
+ const config = JSON.parse(raw);
18
+ const keys = key.split(".");
19
+ let target = config;
20
+ for (let i = 0; i < keys.length - 1; i++) {
21
+ const k = keys[i];
22
+ if (!(k in target)) {
23
+ target[k] = {};
24
+ }
25
+ target = target[k];
26
+ }
27
+ target[keys[keys.length - 1]] = value;
28
+ await writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
29
+ log(`Set ${key} = ${value}`);
30
+ }
31
+ catch (e) {
32
+ logError(`Failed to update config: ${e}`);
33
+ process.exit(1);
34
+ }
35
+ });
36
+ configCommand
37
+ .command("show")
38
+ .description("Show current configuration")
39
+ .action(async () => {
40
+ const root = findProjectRoot();
41
+ const configPath = join(root, "inkos.json");
42
+ try {
43
+ const raw = await readFile(configPath, "utf-8");
44
+ const config = JSON.parse(raw);
45
+ // Mask API key
46
+ if (config.llm?.apiKey) {
47
+ const key = config.llm.apiKey;
48
+ config.llm.apiKey = key.slice(0, 8) + "..." + key.slice(-4);
49
+ }
50
+ log(JSON.stringify(config, null, 2));
51
+ }
52
+ catch (e) {
53
+ logError(`Failed to read config: ${e}`);
54
+ process.exit(1);
55
+ }
56
+ });
57
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { Command } from "commander";
2
+ export declare const upCommand: Command;
3
+ export declare const downCommand: Command;
4
+ //# sourceMappingURL=daemon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,eAAO,MAAM,SAAS,SAsElB,CAAC;AAEL,eAAO,MAAM,WAAW,SAkBpB,CAAC"}
@@ -0,0 +1,93 @@
1
+ import { Command } from "commander";
2
+ import { Scheduler, createLLMClient } from "@actalk/inkos-core";
3
+ import { loadConfig, findProjectRoot, log, logError } from "../utils.js";
4
+ import { writeFile, readFile, unlink } from "node:fs/promises";
5
+ import { join } from "node:path";
6
+ const PID_FILE = "inkos.pid";
7
+ export const upCommand = new Command("up")
8
+ .description("Start the InkOS daemon (autonomous mode)")
9
+ .option("--foreground", "Run in foreground instead of background")
10
+ .action(async (opts) => {
11
+ try {
12
+ const config = await loadConfig();
13
+ const client = createLLMClient(config.llm);
14
+ const root = findProjectRoot();
15
+ // Check if already running
16
+ const pidPath = join(root, PID_FILE);
17
+ try {
18
+ const existingPid = await readFile(pidPath, "utf-8");
19
+ logError(`Daemon already running (PID: ${existingPid.trim()}). Run 'inkos down' first.`);
20
+ process.exit(1);
21
+ }
22
+ catch {
23
+ // No PID file, good
24
+ }
25
+ log("Starting InkOS daemon...");
26
+ log(` Write cycle: ${config.daemon.schedule.writeCron}`);
27
+ log(` Radar scan: ${config.daemon.schedule.radarCron}`);
28
+ log(` Max concurrent books: ${config.daemon.maxConcurrentBooks}`);
29
+ log("");
30
+ // Write PID file
31
+ await writeFile(pidPath, String(process.pid), "utf-8");
32
+ const scheduler = new Scheduler({
33
+ client,
34
+ model: config.llm.model,
35
+ projectRoot: root,
36
+ notifyChannels: config.notify,
37
+ radarCron: config.daemon.schedule.radarCron,
38
+ writeCron: config.daemon.schedule.writeCron,
39
+ auditCron: config.daemon.schedule.auditCron,
40
+ maxConcurrentBooks: config.daemon.maxConcurrentBooks,
41
+ onChapterComplete: (bookId, chapter, status) => {
42
+ const icon = status === "approved" ? "+" : "!";
43
+ log(` [${icon}] ${bookId} Ch.${chapter} — ${status}`);
44
+ },
45
+ onError: (bookId, error) => {
46
+ logError(`${bookId}: ${error.message}`);
47
+ },
48
+ });
49
+ // Handle shutdown
50
+ const shutdown = async () => {
51
+ log("\nShutting down daemon...");
52
+ scheduler.stop();
53
+ try {
54
+ await unlink(pidPath);
55
+ }
56
+ catch {
57
+ // ignore
58
+ }
59
+ process.exit(0);
60
+ };
61
+ process.on("SIGINT", shutdown);
62
+ process.on("SIGTERM", shutdown);
63
+ await scheduler.start();
64
+ log("Daemon running. Press Ctrl+C to stop.");
65
+ // Keep process alive
66
+ await new Promise(() => { });
67
+ }
68
+ catch (e) {
69
+ logError(`Failed to start daemon: ${e}`);
70
+ process.exit(1);
71
+ }
72
+ });
73
+ export const downCommand = new Command("down")
74
+ .description("Stop the InkOS daemon")
75
+ .action(async () => {
76
+ const root = findProjectRoot();
77
+ const pidPath = join(root, PID_FILE);
78
+ try {
79
+ const pid = (await readFile(pidPath, "utf-8")).trim();
80
+ try {
81
+ process.kill(parseInt(pid, 10), "SIGTERM");
82
+ log(`Daemon (PID: ${pid}) stopped.`);
83
+ }
84
+ catch {
85
+ log(`Daemon (PID: ${pid}) not found. Cleaning up.`);
86
+ }
87
+ await unlink(pidPath);
88
+ }
89
+ catch {
90
+ log("No daemon running.");
91
+ }
92
+ });
93
+ //# sourceMappingURL=daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare const doctorCommand: Command;
3
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,aAAa,SAwEtB,CAAC"}
@@ -0,0 +1,76 @@
1
+ import { Command } from "commander";
2
+ import { readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { findProjectRoot, log } from "../utils.js";
5
+ export const doctorCommand = new Command("doctor")
6
+ .description("Check environment and project health")
7
+ .action(async () => {
8
+ const checks = [];
9
+ const root = findProjectRoot();
10
+ // 1. Check Node.js version
11
+ const nodeVersion = process.version;
12
+ const major = parseInt(nodeVersion.slice(1).split(".")[0], 10);
13
+ checks.push({
14
+ name: "Node.js >= 20",
15
+ ok: major >= 20,
16
+ detail: nodeVersion,
17
+ });
18
+ // 2. Check inkos.json exists
19
+ try {
20
+ await readFile(join(root, "inkos.json"), "utf-8");
21
+ checks.push({ name: "inkos.json", ok: true, detail: "Found" });
22
+ }
23
+ catch {
24
+ checks.push({ name: "inkos.json", ok: false, detail: "Not found. Run 'inkos init'" });
25
+ }
26
+ // 3. Check .env exists
27
+ try {
28
+ await readFile(join(root, ".env"), "utf-8");
29
+ checks.push({ name: ".env", ok: true, detail: "Found" });
30
+ }
31
+ catch {
32
+ checks.push({ name: ".env", ok: false, detail: "Not found" });
33
+ }
34
+ // 4. Check LLM API key
35
+ try {
36
+ const raw = await readFile(join(root, "inkos.json"), "utf-8");
37
+ const config = JSON.parse(raw);
38
+ const hasKey = config.llm?.apiKey && config.llm.apiKey.length > 10;
39
+ checks.push({
40
+ name: "LLM API Key",
41
+ ok: hasKey,
42
+ detail: hasKey ? "Configured" : "Missing or too short",
43
+ });
44
+ }
45
+ catch {
46
+ checks.push({ name: "LLM API Key", ok: false, detail: "Cannot read config" });
47
+ }
48
+ // 5. Check books directory
49
+ try {
50
+ const { StateManager } = await import("@actalk/inkos-core");
51
+ const state = new StateManager(root);
52
+ const books = await state.listBooks();
53
+ checks.push({
54
+ name: "Books",
55
+ ok: true,
56
+ detail: `${books.length} book(s) found`,
57
+ });
58
+ }
59
+ catch {
60
+ checks.push({ name: "Books", ok: true, detail: "0 books" });
61
+ }
62
+ // Output
63
+ log("InkOS Doctor\n");
64
+ for (const check of checks) {
65
+ const icon = check.ok ? "[OK]" : "[!!]";
66
+ log(` ${icon} ${check.name}: ${check.detail}`);
67
+ }
68
+ const failed = checks.filter((c) => !c.ok);
69
+ if (failed.length > 0) {
70
+ log(`\n${failed.length} issue(s) found.`);
71
+ }
72
+ else {
73
+ log("\nAll checks passed.");
74
+ }
75
+ });
76
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare const exportCommand: Command;
3
+ //# sourceMappingURL=export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,eAAO,MAAM,aAAa,SA2DtB,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { Command } from "commander";
2
+ import { StateManager } from "@actalk/inkos-core";
3
+ import { readFile, writeFile } from "node:fs/promises";
4
+ import { join } from "node:path";
5
+ import { findProjectRoot, log, logError } from "../utils.js";
6
+ export const exportCommand = new Command("export")
7
+ .description("Export book chapters to a single file")
8
+ .argument("<book-id>", "Book ID")
9
+ .option("--format <format>", "Output format (txt, md)", "txt")
10
+ .option("--output <path>", "Output file path")
11
+ .option("--approved-only", "Only export approved chapters")
12
+ .action(async (bookId, opts) => {
13
+ try {
14
+ const root = findProjectRoot();
15
+ const state = new StateManager(root);
16
+ const book = await state.loadBookConfig(bookId);
17
+ const index = await state.loadChapterIndex(bookId);
18
+ const bookDir = state.bookDir(bookId);
19
+ const chaptersDir = join(bookDir, "chapters");
20
+ const chapters = opts.approvedOnly
21
+ ? index.filter((ch) => ch.status === "approved")
22
+ : index;
23
+ if (chapters.length === 0) {
24
+ logError("No chapters to export.");
25
+ process.exit(1);
26
+ }
27
+ const parts = [];
28
+ if (opts.format === "md") {
29
+ parts.push(`# ${book.title}\n`);
30
+ parts.push(`---\n`);
31
+ }
32
+ else {
33
+ parts.push(`${book.title}\n\n`);
34
+ }
35
+ for (const ch of chapters) {
36
+ const paddedNum = String(ch.number).padStart(4, "0");
37
+ const files = await import("node:fs/promises").then((fs) => fs.readdir(chaptersDir));
38
+ const match = files.find((f) => f.startsWith(paddedNum));
39
+ if (!match)
40
+ continue;
41
+ const content = await readFile(join(chaptersDir, match), "utf-8");
42
+ parts.push(content);
43
+ parts.push("\n\n");
44
+ }
45
+ const totalWords = chapters.reduce((sum, ch) => sum + ch.wordCount, 0);
46
+ const outputPath = opts.output ?? join(root, `${bookId}_export.${opts.format}`);
47
+ await writeFile(outputPath, parts.join("\n"), "utf-8");
48
+ log(`Exported ${chapters.length} chapters (${totalWords} words)`);
49
+ log(`Output: ${outputPath}`);
50
+ }
51
+ catch (e) {
52
+ logError(`Failed to export: ${e}`);
53
+ process.exit(1);
54
+ }
55
+ });
56
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare const initCommand: Command;
3
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,WAAW,SAiEpB,CAAC"}
@@ -0,0 +1,54 @@
1
+ import { Command } from "commander";
2
+ import { writeFile, mkdir } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { log, logError } from "../utils.js";
5
+ export const initCommand = new Command("init")
6
+ .description("Initialize a new InkOS project")
7
+ .argument("[name]", "Project name", "my-novel-project")
8
+ .action(async (name) => {
9
+ const projectDir = join(process.cwd(), name);
10
+ try {
11
+ await mkdir(projectDir, { recursive: true });
12
+ await mkdir(join(projectDir, "books"), { recursive: true });
13
+ await mkdir(join(projectDir, "radar"), { recursive: true });
14
+ const config = {
15
+ name,
16
+ version: "0.1.0",
17
+ llm: {
18
+ provider: "anthropic",
19
+ baseUrl: process.env.INKOS_LLM_BASE_URL ?? "https://api.anthropic.com/v1",
20
+ apiKey: process.env.INKOS_LLM_API_KEY ?? "",
21
+ model: process.env.INKOS_LLM_MODEL ?? "claude-sonnet-4-5-20250514",
22
+ },
23
+ notify: [],
24
+ daemon: {
25
+ schedule: {
26
+ radarCron: "0 9 * * *",
27
+ writeCron: "0 14 * * *",
28
+ auditCron: "0 17 * * *",
29
+ },
30
+ maxConcurrentBooks: 3,
31
+ },
32
+ };
33
+ await writeFile(join(projectDir, "inkos.json"), JSON.stringify(config, null, 2), "utf-8");
34
+ await writeFile(join(projectDir, ".env"), [
35
+ "INKOS_LLM_PROVIDER=anthropic",
36
+ "INKOS_LLM_BASE_URL=https://api.anthropic.com/v1",
37
+ "INKOS_LLM_API_KEY=your-api-key-here",
38
+ "INKOS_LLM_MODEL=claude-sonnet-4-5-20250514",
39
+ ].join("\n"), "utf-8");
40
+ await writeFile(join(projectDir, ".gitignore"), [".env", "node_modules/", ".DS_Store"].join("\n"), "utf-8");
41
+ log(`Project initialized at ${projectDir}`);
42
+ log("");
43
+ log("Next steps:");
44
+ log(` cd ${name}`);
45
+ log(" # Edit .env with your LLM API credentials");
46
+ log(" inkos book create --title '我的小说' --genre xuanhuan --platform tomato");
47
+ log(" inkos write next <book-id>");
48
+ }
49
+ catch (e) {
50
+ logError(`Failed to initialize project: ${e}`);
51
+ process.exit(1);
52
+ }
53
+ });
54
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,gCAAgC,CAAC;KAC7C,QAAQ,CAAC,QAAQ,EAAE,cAAc,EAAE,kBAAkB,CAAC;KACtD,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;IAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;IAE7C,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE5D,MAAM,MAAM,GAAG;YACb,IAAI;YACJ,OAAO,EAAE,OAAO;YAChB,GAAG,EAAE;gBACH,QAAQ,EAAE,WAAW;gBACrB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,8BAA8B;gBACzE,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE;gBAC3C,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,4BAA4B;aACnE;YACD,MAAM,EAAE,EAAE;YACV,MAAM,EAAE;gBACN,QAAQ,EAAE;oBACR,SAAS,EAAE,WAAW;oBACtB,SAAS,EAAE,YAAY;oBACvB,SAAS,EAAE,YAAY;iBACxB;gBACD,kBAAkB,EAAE,CAAC;aACtB;SACF,CAAC;QAEF,MAAM,SAAS,CACb,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,EAC9B,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAC/B,OAAO,CACR,CAAC;QAEF,MAAM,SAAS,CACb,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,EACxB;YACE,8BAA8B;YAC9B,iDAAiD;YACjD,qCAAqC;YACrC,4CAA4C;SAC7C,CAAC,IAAI,CAAC,IAAI,CAAC,EACZ,OAAO,CACR,CAAC;QAEF,MAAM,SAAS,CACb,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,EAC9B,CAAC,MAAM,EAAE,eAAe,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EACjD,OAAO,CACR,CAAC;QAEF,GAAG,CAAC,0BAA0B,UAAU,EAAE,CAAC,CAAC;QAC5C,GAAG,CAAC,EAAE,CAAC,CAAC;QACR,GAAG,CAAC,aAAa,CAAC,CAAC;QACnB,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;QACpB,GAAG,CAAC,6CAA6C,CAAC,CAAC;QACnD,GAAG,CAAC,uEAAuE,CAAC,CAAC;QAC7E,GAAG,CAAC,8BAA8B,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,QAAQ,CAAC,iCAAiC,CAAC,EAAE,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare const radarCommand: Command;
3
+ //# sourceMappingURL=radar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radar.d.ts","sourceRoot":"","sources":["../../src/commands/radar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,eAAO,MAAM,YAAY,SACY,CAAC"}
@@ -0,0 +1,45 @@
1
+ import { Command } from "commander";
2
+ import { PipelineRunner } from "@actalk/inkos-core";
3
+ import { loadConfig, createClient, findProjectRoot, log, logError } from "../utils.js";
4
+ import { writeFile, mkdir } from "node:fs/promises";
5
+ import { join } from "node:path";
6
+ export const radarCommand = new Command("radar")
7
+ .description("Market intelligence");
8
+ radarCommand
9
+ .command("scan")
10
+ .description("Scan market for opportunities")
11
+ .option("--platforms <platforms>", "Platforms to scan (comma-separated)", "tomato,feilu")
12
+ .action(async (opts) => {
13
+ try {
14
+ const config = await loadConfig();
15
+ const client = createClient(config);
16
+ const root = findProjectRoot();
17
+ const pipeline = new PipelineRunner({
18
+ client,
19
+ model: config.llm.model,
20
+ projectRoot: root,
21
+ });
22
+ log("Scanning market...");
23
+ const result = await pipeline.runRadar();
24
+ log(`\nMarket Summary:\n${result.marketSummary}\n`);
25
+ log("Recommendations:");
26
+ for (const rec of result.recommendations) {
27
+ log(` [${(rec.confidence * 100).toFixed(0)}%] ${rec.platform}/${rec.genre}`);
28
+ log(` Concept: ${rec.concept}`);
29
+ log(` Reasoning: ${rec.reasoning}`);
30
+ log(` Benchmarks: ${rec.benchmarkTitles.join(", ")}`);
31
+ log("");
32
+ }
33
+ // Save radar result
34
+ const radarDir = join(root, "radar");
35
+ await mkdir(radarDir, { recursive: true });
36
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
37
+ await writeFile(join(radarDir, `scan-${timestamp}.json`), JSON.stringify(result, null, 2), "utf-8");
38
+ log(`Radar result saved to radar/scan-${timestamp}.json`);
39
+ }
40
+ catch (e) {
41
+ logError(`Radar scan failed: ${e}`);
42
+ process.exit(1);
43
+ }
44
+ });
45
+ //# sourceMappingURL=radar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radar.js","sourceRoot":"","sources":["../../src/commands/radar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,qBAAqB,CAAC,CAAC;AAEtC,YAAY;KACT,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,+BAA+B,CAAC;KAC5C,MAAM,CAAC,yBAAyB,EAAE,qCAAqC,EAAE,cAAc,CAAC;KACxF,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;QAE/B,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC;YAClC,MAAM;YACN,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK;YACvB,WAAW,EAAE,IAAI;SAClB,CAAC,CAAC;QAEH,GAAG,CAAC,oBAAoB,CAAC,CAAC;QAE1B,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAEzC,GAAG,CAAC,sBAAsB,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC;QACpD,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAExB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;YACzC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;YAC9E,GAAG,CAAC,gBAAgB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACnC,GAAG,CAAC,kBAAkB,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;YACvC,GAAG,CAAC,mBAAmB,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACzD,GAAG,CAAC,EAAE,CAAC,CAAC;QACV,CAAC;QAED,oBAAoB;QACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACrC,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACjE,MAAM,SAAS,CACb,IAAI,CAAC,QAAQ,EAAE,QAAQ,SAAS,OAAO,CAAC,EACxC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAC/B,OAAO,CACR,CAAC;QAEF,GAAG,CAAC,oCAAoC,SAAS,OAAO,CAAC,CAAC;IAC5D,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare const reviewCommand: Command;
3
+ //# sourceMappingURL=review.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/commands/review.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,eAAO,MAAM,aAAa,SACmB,CAAC"}
@@ -0,0 +1,123 @@
1
+ import { Command } from "commander";
2
+ import { StateManager } from "@actalk/inkos-core";
3
+ import { findProjectRoot, log, logError } from "../utils.js";
4
+ export const reviewCommand = new Command("review")
5
+ .description("Review and approve chapters");
6
+ reviewCommand
7
+ .command("list")
8
+ .description("List chapters pending review")
9
+ .argument("[book-id]", "Book ID (optional, lists all books if omitted)")
10
+ .action(async (bookId) => {
11
+ try {
12
+ const root = findProjectRoot();
13
+ const state = new StateManager(root);
14
+ const bookIds = bookId ? [bookId] : await state.listBooks();
15
+ for (const id of bookIds) {
16
+ const index = await state.loadChapterIndex(id);
17
+ const pending = index.filter((ch) => ch.status === "ready-for-review" || ch.status === "audit-failed");
18
+ if (pending.length === 0)
19
+ continue;
20
+ const book = await state.loadBookConfig(id);
21
+ log(`\n${book.title} (${id}):`);
22
+ for (const ch of pending) {
23
+ log(` Ch.${ch.number} "${ch.title}" | ${ch.wordCount}字 | ${ch.status}`);
24
+ if (ch.auditIssues.length > 0) {
25
+ for (const issue of ch.auditIssues) {
26
+ log(` - ${issue}`);
27
+ }
28
+ }
29
+ }
30
+ }
31
+ }
32
+ catch (e) {
33
+ logError(`Failed to list reviews: ${e}`);
34
+ process.exit(1);
35
+ }
36
+ });
37
+ reviewCommand
38
+ .command("approve")
39
+ .description("Approve a chapter")
40
+ .argument("<book-id>", "Book ID")
41
+ .argument("<chapter>", "Chapter number")
42
+ .action(async (bookId, chapterStr) => {
43
+ try {
44
+ const root = findProjectRoot();
45
+ const state = new StateManager(root);
46
+ const chapterNum = parseInt(chapterStr, 10);
47
+ const index = [...(await state.loadChapterIndex(bookId))];
48
+ const idx = index.findIndex((ch) => ch.number === chapterNum);
49
+ if (idx === -1) {
50
+ logError(`Chapter ${chapterNum} not found`);
51
+ process.exit(1);
52
+ }
53
+ index[idx] = {
54
+ ...index[idx],
55
+ status: "approved",
56
+ updatedAt: new Date().toISOString(),
57
+ };
58
+ await state.saveChapterIndex(bookId, index);
59
+ log(`Chapter ${chapterNum} approved.`);
60
+ }
61
+ catch (e) {
62
+ logError(`Failed to approve: ${e}`);
63
+ process.exit(1);
64
+ }
65
+ });
66
+ reviewCommand
67
+ .command("approve-all")
68
+ .description("Approve all pending chapters for a book")
69
+ .argument("<book-id>", "Book ID")
70
+ .action(async (bookId) => {
71
+ try {
72
+ const root = findProjectRoot();
73
+ const state = new StateManager(root);
74
+ const index = [...(await state.loadChapterIndex(bookId))];
75
+ let count = 0;
76
+ const now = new Date().toISOString();
77
+ const updated = index.map((ch) => {
78
+ if (ch.status === "ready-for-review" || ch.status === "audit-failed") {
79
+ count++;
80
+ return { ...ch, status: "approved", updatedAt: now };
81
+ }
82
+ return ch;
83
+ });
84
+ await state.saveChapterIndex(bookId, updated);
85
+ log(`${count} chapter(s) approved.`);
86
+ }
87
+ catch (e) {
88
+ logError(`Failed to approve: ${e}`);
89
+ process.exit(1);
90
+ }
91
+ });
92
+ reviewCommand
93
+ .command("reject")
94
+ .description("Reject a chapter")
95
+ .argument("<book-id>", "Book ID")
96
+ .argument("<chapter>", "Chapter number")
97
+ .option("--reason <reason>", "Rejection reason")
98
+ .action(async (bookId, chapterStr, opts) => {
99
+ try {
100
+ const root = findProjectRoot();
101
+ const state = new StateManager(root);
102
+ const chapterNum = parseInt(chapterStr, 10);
103
+ const index = [...(await state.loadChapterIndex(bookId))];
104
+ const idx = index.findIndex((ch) => ch.number === chapterNum);
105
+ if (idx === -1) {
106
+ logError(`Chapter ${chapterNum} not found`);
107
+ process.exit(1);
108
+ }
109
+ index[idx] = {
110
+ ...index[idx],
111
+ status: "rejected",
112
+ reviewNote: opts.reason ?? "Rejected without reason",
113
+ updatedAt: new Date().toISOString(),
114
+ };
115
+ await state.saveChapterIndex(bookId, index);
116
+ log(`Chapter ${chapterNum} rejected.`);
117
+ }
118
+ catch (e) {
119
+ logError(`Failed to reject: ${e}`);
120
+ process.exit(1);
121
+ }
122
+ });
123
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/commands/review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare const statusCommand: Command;
3
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,eAAO,MAAM,aAAa,SAyCtB,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { Command } from "commander";
2
+ import { StateManager } from "@actalk/inkos-core";
3
+ import { findProjectRoot, log, logError } from "../utils.js";
4
+ export const statusCommand = new Command("status")
5
+ .description("Show project status")
6
+ .action(async () => {
7
+ try {
8
+ const root = findProjectRoot();
9
+ const state = new StateManager(root);
10
+ const bookIds = await state.listBooks();
11
+ log(`InkOS Project: ${root}`);
12
+ log(`Books: ${bookIds.length}`);
13
+ log("");
14
+ for (const id of bookIds) {
15
+ const book = await state.loadBookConfig(id);
16
+ const index = await state.loadChapterIndex(id);
17
+ const nextChapter = await state.getNextChapterNumber(id);
18
+ const approved = index.filter((ch) => ch.status === "approved").length;
19
+ const pending = index.filter((ch) => ch.status === "ready-for-review").length;
20
+ const failed = index.filter((ch) => ch.status === "audit-failed").length;
21
+ log(` ${book.title} (${id})`);
22
+ log(` Status: ${book.status}`);
23
+ log(` Platform: ${book.platform} | Genre: ${book.genre}`);
24
+ const totalWords = index.reduce((sum, ch) => sum + ch.wordCount, 0);
25
+ const avgWords = index.length > 0 ? Math.round(totalWords / index.length) : 0;
26
+ log(` Chapters: ${nextChapter - 1} / ${book.targetChapters}`);
27
+ log(` Words: ${totalWords.toLocaleString()} (avg ${avgWords}/ch)`);
28
+ log(` Approved: ${approved} | Pending: ${pending} | Failed: ${failed}`);
29
+ log("");
30
+ }
31
+ }
32
+ catch (e) {
33
+ logError(`Failed to get status: ${e}`);
34
+ process.exit(1);
35
+ }
36
+ });
37
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE7D,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,qBAAqB,CAAC;KAClC,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;QAErC,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE,CAAC;QAExC,GAAG,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC;QAC9B,GAAG,CAAC,UAAU,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAChC,GAAG,CAAC,EAAE,CAAC,CAAC;QAER,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;YAC5C,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;YAC/C,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC;YAEzD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,MAAM,CAAC;YACvE,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAC1B,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,KAAK,kBAAkB,CACzC,CAAC,MAAM,CAAC;YACT,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CACzB,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,KAAK,cAAc,CACrC,CAAC,MAAM,CAAC;YAET,GAAG,CAAC,KAAK,IAAI,CAAC,KAAK,KAAK,EAAE,GAAG,CAAC,CAAC;YAC/B,GAAG,CAAC,eAAe,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YAClC,GAAG,CAAC,iBAAiB,IAAI,CAAC,QAAQ,aAAa,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YAC7D,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YACpE,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAE9E,GAAG,CAAC,iBAAiB,WAAW,GAAG,CAAC,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;YACjE,GAAG,CAAC,cAAc,UAAU,CAAC,cAAc,EAAE,SAAS,QAAQ,MAAM,CAAC,CAAC;YACtE,GAAG,CAAC,iBAAiB,QAAQ,eAAe,OAAO,cAAc,MAAM,EAAE,CAAC,CAAC;YAC3E,GAAG,CAAC,EAAE,CAAC,CAAC;QACV,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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare const writeCommand: Command;
3
+ //# sourceMappingURL=write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/commands/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,eAAO,MAAM,YAAY,SACO,CAAC"}
@@ -0,0 +1,113 @@
1
+ import { Command } from "commander";
2
+ import { PipelineRunner, StateManager } from "@actalk/inkos-core";
3
+ import { readdir, unlink } from "node:fs/promises";
4
+ import { join } from "node:path";
5
+ import { loadConfig, createClient, findProjectRoot, log, logError } from "../utils.js";
6
+ export const writeCommand = new Command("write")
7
+ .description("Write chapters");
8
+ writeCommand
9
+ .command("next")
10
+ .description("Write the next chapter for a book")
11
+ .argument("<book-id>", "Book ID")
12
+ .option("--count <n>", "Number of chapters to write", "1")
13
+ .action(async (bookId, opts) => {
14
+ try {
15
+ const config = await loadConfig();
16
+ const client = createClient(config);
17
+ const root = findProjectRoot();
18
+ const pipeline = new PipelineRunner({
19
+ client,
20
+ model: config.llm.model,
21
+ projectRoot: root,
22
+ notifyChannels: config.notify,
23
+ });
24
+ const count = parseInt(opts.count, 10);
25
+ for (let i = 0; i < count; i++) {
26
+ log(`Writing chapter for "${bookId}"...`);
27
+ const result = await pipeline.writeNextChapter(bookId);
28
+ log(` Chapter ${result.chapterNumber}: ${result.title}`);
29
+ log(` Words: ${result.wordCount}`);
30
+ log(` Audit: ${result.auditResult.passed ? "PASSED" : "NEEDS REVIEW"}`);
31
+ if (result.revised) {
32
+ log(" Auto-revised: YES (critical issues were fixed)");
33
+ }
34
+ log(` Status: ${result.status}`);
35
+ if (result.auditResult.issues.length > 0) {
36
+ log(" Issues:");
37
+ for (const issue of result.auditResult.issues) {
38
+ log(` [${issue.severity}] ${issue.category}: ${issue.description}`);
39
+ }
40
+ }
41
+ log("");
42
+ }
43
+ log("Done.");
44
+ }
45
+ catch (e) {
46
+ logError(`Failed to write chapter: ${e}`);
47
+ process.exit(1);
48
+ }
49
+ });
50
+ writeCommand
51
+ .command("rewrite")
52
+ .description("Re-generate a specific chapter (removes it and writes fresh)")
53
+ .argument("<book-id>", "Book ID")
54
+ .argument("<chapter>", "Chapter number to rewrite")
55
+ .action(async (bookId, chapterStr) => {
56
+ try {
57
+ const config = await loadConfig();
58
+ const client = createClient(config);
59
+ const root = findProjectRoot();
60
+ const chapterNum = parseInt(chapterStr, 10);
61
+ const state = new StateManager(root);
62
+ const bookDir = state.bookDir(bookId);
63
+ const chaptersDir = join(bookDir, "chapters");
64
+ // Remove existing chapter file
65
+ const files = await readdir(chaptersDir);
66
+ const paddedNum = String(chapterNum).padStart(4, "0");
67
+ const existing = files.filter((f) => f.startsWith(paddedNum) && f.endsWith(".md"));
68
+ for (const f of existing) {
69
+ await unlink(join(chaptersDir, f));
70
+ log(`Removed: ${f}`);
71
+ }
72
+ // Remove from index (and all chapters after it)
73
+ const index = await state.loadChapterIndex(bookId);
74
+ const trimmed = index.filter((ch) => ch.number < chapterNum);
75
+ await state.saveChapterIndex(bookId, trimmed);
76
+ // Also remove later chapter files since state will be rolled back
77
+ const laterFiles = files.filter((f) => {
78
+ const num = parseInt(f.slice(0, 4), 10);
79
+ return num > chapterNum && f.endsWith(".md");
80
+ });
81
+ for (const f of laterFiles) {
82
+ await unlink(join(chaptersDir, f));
83
+ log(`Removed later chapter: ${f}`);
84
+ }
85
+ // Restore state to previous chapter's end-state
86
+ if (chapterNum > 1) {
87
+ const restored = await state.restoreState(bookId, chapterNum - 1);
88
+ if (restored) {
89
+ log(`State restored from chapter ${chapterNum - 1} snapshot.`);
90
+ }
91
+ else {
92
+ log(`Warning: no snapshot for chapter ${chapterNum - 1}. Using current state.`);
93
+ }
94
+ }
95
+ log(`Regenerating chapter ${chapterNum}...`);
96
+ const pipeline = new PipelineRunner({
97
+ client,
98
+ model: config.llm.model,
99
+ projectRoot: root,
100
+ notifyChannels: config.notify,
101
+ });
102
+ const result = await pipeline.writeNextChapter(bookId);
103
+ log(` Chapter ${result.chapterNumber}: ${result.title}`);
104
+ log(` Words: ${result.wordCount}`);
105
+ log(` Audit: ${result.auditResult.passed ? "PASSED" : "NEEDS REVIEW"}`);
106
+ log(` Status: ${result.status}`);
107
+ }
108
+ catch (e) {
109
+ logError(`Failed to rewrite chapter: ${e}`);
110
+ process.exit(1);
111
+ }
112
+ });
113
+ //# sourceMappingURL=write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/commands/write.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { initCommand } from "./commands/init.js";
4
+ import { configCommand } from "./commands/config.js";
5
+ import { bookCommand } from "./commands/book.js";
6
+ import { writeCommand } from "./commands/write.js";
7
+ import { reviewCommand } from "./commands/review.js";
8
+ import { statusCommand } from "./commands/status.js";
9
+ import { radarCommand } from "./commands/radar.js";
10
+ import { upCommand, downCommand } from "./commands/daemon.js";
11
+ import { doctorCommand } from "./commands/doctor.js";
12
+ import { exportCommand } from "./commands/export.js";
13
+ const program = new Command();
14
+ program
15
+ .name("inkos")
16
+ .description("InkOS — Multi-agent novel production system")
17
+ .version("0.1.0");
18
+ program.addCommand(initCommand);
19
+ program.addCommand(configCommand);
20
+ program.addCommand(bookCommand);
21
+ program.addCommand(writeCommand);
22
+ program.addCommand(reviewCommand);
23
+ program.addCommand(statusCommand);
24
+ program.addCommand(radarCommand);
25
+ program.addCommand(upCommand);
26
+ program.addCommand(downCommand);
27
+ program.addCommand(doctorCommand);
28
+ program.addCommand(exportCommand);
29
+ program.parse();
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,OAAO,CAAC;KACb,WAAW,CAAC,6CAA6C,CAAC;KAC1D,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;AAC9B,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAElC,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type ProjectConfig } from "@actalk/inkos-core";
2
+ export declare function findProjectRoot(): string;
3
+ export declare function loadConfig(): Promise<ProjectConfig>;
4
+ export declare function createClient(config: ProjectConfig): import("openai").OpenAI;
5
+ export declare function log(message: string): void;
6
+ export declare function logError(message: string): void;
7
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmB,KAAK,aAAa,EAAuB,MAAM,oBAAoB,CAAC;AAE9F,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC,CAezD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,2BAEjD;AAED,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEzC;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE9C"}
package/dist/utils.js ADDED
@@ -0,0 +1,30 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { config as loadEnv } from "dotenv";
4
+ import { createLLMClient, ProjectConfigSchema } from "@actalk/inkos-core";
5
+ export function findProjectRoot() {
6
+ return process.cwd();
7
+ }
8
+ export async function loadConfig() {
9
+ const root = findProjectRoot();
10
+ // Load .env from project root
11
+ loadEnv({ path: join(root, ".env") });
12
+ const configPath = join(root, "inkos.json");
13
+ try {
14
+ const raw = await readFile(configPath, "utf-8");
15
+ return ProjectConfigSchema.parse(JSON.parse(raw));
16
+ }
17
+ catch (e) {
18
+ throw new Error(`Failed to load inkos.json from ${root}. Run 'inkos init' first.`);
19
+ }
20
+ }
21
+ export function createClient(config) {
22
+ return createLLMClient(config.llm);
23
+ }
24
+ export function log(message) {
25
+ process.stdout.write(`${message}\n`);
26
+ }
27
+ export function logError(message) {
28
+ process.stderr.write(`[ERROR] ${message}\n`);
29
+ }
30
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAW,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAsB,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9F,MAAM,UAAU,eAAe;IAC7B,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC;AACvB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAE/B,8BAA8B;IAC9B,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAEtC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,kCAAkC,IAAI,2BAA2B,CAClE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAqB;IAChD,OAAO,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,OAAe;IACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,OAAe;IACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,OAAO,IAAI,CAAC,CAAC;AAC/C,CAAC"}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@actalk/inkos",
3
+ "version": "0.1.0",
4
+ "description": "InkOS CLI — multi-agent novel production system",
5
+ "type": "module",
6
+ "bin": {
7
+ "inkos": "dist/index.js"
8
+ },
9
+ "files": ["dist"],
10
+ "license": "MIT",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/Narcooo/inkos.git",
14
+ "directory": "packages/cli"
15
+ },
16
+ "scripts": {
17
+ "build": "tsc",
18
+ "dev": "tsc --watch",
19
+ "test": "vitest run",
20
+ "typecheck": "tsc --noEmit"
21
+ },
22
+ "dependencies": {
23
+ "@actalk/inkos-core": "workspace:*",
24
+ "commander": "^13.0.0",
25
+ "chalk": "^5.4.0",
26
+ "ora": "^8.2.0",
27
+ "inquirer": "^12.3.0",
28
+ "dotenv": "^16.4.0"
29
+ },
30
+ "devDependencies": {
31
+ "typescript": "^5.8.0",
32
+ "vitest": "^3.0.0",
33
+ "@types/node": "^22.0.0"
34
+ }
35
+ }