@actalk/inkos-core 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/dist/__tests__/models.test.d.ts +2 -0
- package/dist/__tests__/models.test.d.ts.map +1 -0
- package/dist/__tests__/models.test.js +328 -0
- package/dist/__tests__/models.test.js.map +1 -0
- package/dist/__tests__/state-manager.test.d.ts +2 -0
- package/dist/__tests__/state-manager.test.d.ts.map +1 -0
- package/dist/__tests__/state-manager.test.js +264 -0
- package/dist/__tests__/state-manager.test.js.map +1 -0
- package/dist/__tests__/writer-parser.test.d.ts +2 -0
- package/dist/__tests__/writer-parser.test.d.ts.map +1 -0
- package/dist/__tests__/writer-parser.test.js +183 -0
- package/dist/__tests__/writer-parser.test.js.map +1 -0
- package/dist/agents/architect.d.ts +16 -0
- package/dist/agents/architect.d.ts.map +1 -0
- package/dist/agents/architect.js +85 -0
- package/dist/agents/architect.js.map +1 -0
- package/dist/agents/base.d.ts +18 -0
- package/dist/agents/base.d.ts.map +1 -0
- package/dist/agents/base.js +11 -0
- package/dist/agents/base.js.map +1 -0
- package/dist/agents/continuity.d.ts +19 -0
- package/dist/agents/continuity.d.ts.map +1 -0
- package/dist/agents/continuity.js +114 -0
- package/dist/agents/continuity.js.map +1 -0
- package/dist/agents/radar.d.ts +21 -0
- package/dist/agents/radar.d.ts.map +1 -0
- package/dist/agents/radar.js +60 -0
- package/dist/agents/radar.js.map +1 -0
- package/dist/agents/reviser.d.ts +17 -0
- package/dist/agents/reviser.d.ts.map +1 -0
- package/dist/agents/reviser.js +99 -0
- package/dist/agents/reviser.js.map +1 -0
- package/dist/agents/writer.d.ts +30 -0
- package/dist/agents/writer.d.ts.map +1 -0
- package/dist/agents/writer.js +284 -0
- package/dist/agents/writer.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/provider.d.ts +20 -0
- package/dist/llm/provider.d.ts.map +1 -0
- package/dist/llm/provider.js +41 -0
- package/dist/llm/provider.js.map +1 -0
- package/dist/models/book.d.ts +40 -0
- package/dist/models/book.d.ts.map +1 -0
- package/dist/models/book.js +32 -0
- package/dist/models/book.js.map +1 -0
- package/dist/models/chapter.d.ts +33 -0
- package/dist/models/chapter.d.ts.map +1 -0
- package/dist/models/chapter.js +25 -0
- package/dist/models/chapter.js.map +1 -0
- package/dist/models/project.d.ts +189 -0
- package/dist/models/project.d.ts.map +1 -0
- package/dist/models/project.js +44 -0
- package/dist/models/project.js.map +1 -0
- package/dist/models/state.d.ts +48 -0
- package/dist/models/state.d.ts.map +1 -0
- package/dist/models/state.js +6 -0
- package/dist/models/state.js.map +1 -0
- package/dist/notify/dispatcher.d.ts +7 -0
- package/dist/notify/dispatcher.d.ts.map +1 -0
- package/dist/notify/dispatcher.js +27 -0
- package/dist/notify/dispatcher.js.map +1 -0
- package/dist/notify/feishu.d.ts +5 -0
- package/dist/notify/feishu.d.ts.map +1 -0
- package/dist/notify/feishu.js +26 -0
- package/dist/notify/feishu.js.map +1 -0
- package/dist/notify/telegram.d.ts +6 -0
- package/dist/notify/telegram.d.ts.map +1 -0
- package/dist/notify/telegram.js +17 -0
- package/dist/notify/telegram.js.map +1 -0
- package/dist/notify/wechat-work.d.ts +5 -0
- package/dist/notify/wechat-work.d.ts.map +1 -0
- package/dist/notify/wechat-work.js +15 -0
- package/dist/notify/wechat-work.js.map +1 -0
- package/dist/pipeline/runner.d.ts +30 -0
- package/dist/pipeline/runner.d.ts.map +1 -0
- package/dist/pipeline/runner.js +141 -0
- package/dist/pipeline/runner.js.map +1 -0
- package/dist/pipeline/scheduler.d.ts +24 -0
- package/dist/pipeline/scheduler.d.ts.map +1 -0
- package/dist/pipeline/scheduler.js +102 -0
- package/dist/pipeline/scheduler.js.map +1 -0
- package/dist/state/manager.d.ts +20 -0
- package/dist/state/manager.d.ts.map +1 -0
- package/dist/state/manager.js +128 -0
- package/dist/state/manager.js.map +1 -0
- package/package.json +35 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { ArchitectAgent } from "../agents/architect.js";
|
|
2
|
+
import { WriterAgent } from "../agents/writer.js";
|
|
3
|
+
import { ContinuityAuditor } from "../agents/continuity.js";
|
|
4
|
+
import { ReviserAgent } from "../agents/reviser.js";
|
|
5
|
+
import { RadarAgent } from "../agents/radar.js";
|
|
6
|
+
import { StateManager } from "../state/manager.js";
|
|
7
|
+
import { dispatchNotification } from "../notify/dispatcher.js";
|
|
8
|
+
import { writeFile } from "node:fs/promises";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
export class PipelineRunner {
|
|
11
|
+
state;
|
|
12
|
+
config;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = config;
|
|
15
|
+
this.state = new StateManager(config.projectRoot);
|
|
16
|
+
}
|
|
17
|
+
agentCtx(bookId) {
|
|
18
|
+
return {
|
|
19
|
+
client: this.config.client,
|
|
20
|
+
model: this.config.model,
|
|
21
|
+
projectRoot: this.config.projectRoot,
|
|
22
|
+
bookId,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
async runRadar() {
|
|
26
|
+
const radar = new RadarAgent(this.agentCtx());
|
|
27
|
+
return radar.scan(["tomato", "feilu"]);
|
|
28
|
+
}
|
|
29
|
+
async initBook(book) {
|
|
30
|
+
const architect = new ArchitectAgent(this.agentCtx(book.id));
|
|
31
|
+
const bookDir = this.state.bookDir(book.id);
|
|
32
|
+
await this.state.saveBookConfig(book.id, book);
|
|
33
|
+
const foundation = await architect.generateFoundation(book);
|
|
34
|
+
await architect.writeFoundationFiles(bookDir, foundation);
|
|
35
|
+
await this.state.saveChapterIndex(book.id, []);
|
|
36
|
+
}
|
|
37
|
+
async writeNextChapter(bookId) {
|
|
38
|
+
const releaseLock = await this.state.acquireBookLock(bookId);
|
|
39
|
+
try {
|
|
40
|
+
return await this._writeNextChapterLocked(bookId);
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
await releaseLock();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async _writeNextChapterLocked(bookId) {
|
|
47
|
+
const book = await this.state.loadBookConfig(bookId);
|
|
48
|
+
const bookDir = this.state.bookDir(bookId);
|
|
49
|
+
const chapterNumber = await this.state.getNextChapterNumber(bookId);
|
|
50
|
+
// 1. Write chapter
|
|
51
|
+
const writer = new WriterAgent(this.agentCtx(bookId));
|
|
52
|
+
const output = await writer.writeChapter({
|
|
53
|
+
book,
|
|
54
|
+
bookDir,
|
|
55
|
+
chapterNumber,
|
|
56
|
+
});
|
|
57
|
+
// 2. Audit chapter
|
|
58
|
+
const auditor = new ContinuityAuditor(this.agentCtx(bookId));
|
|
59
|
+
let auditResult = await auditor.auditChapter(bookDir, output.content, chapterNumber);
|
|
60
|
+
let finalContent = output.content;
|
|
61
|
+
let finalWordCount = output.wordCount;
|
|
62
|
+
let revised = false;
|
|
63
|
+
// 3. If audit fails, try auto-revise once
|
|
64
|
+
if (!auditResult.passed) {
|
|
65
|
+
const criticalIssues = auditResult.issues.filter((i) => i.severity === "critical");
|
|
66
|
+
if (criticalIssues.length > 0) {
|
|
67
|
+
const reviser = new ReviserAgent(this.agentCtx(bookId));
|
|
68
|
+
const reviseOutput = await reviser.reviseChapter(bookDir, output.content, chapterNumber, auditResult.issues);
|
|
69
|
+
if (reviseOutput.revisedContent.length > 0) {
|
|
70
|
+
finalContent = reviseOutput.revisedContent;
|
|
71
|
+
finalWordCount = reviseOutput.wordCount;
|
|
72
|
+
revised = true;
|
|
73
|
+
// Re-audit the revised content
|
|
74
|
+
auditResult = await auditor.auditChapter(bookDir, finalContent, chapterNumber);
|
|
75
|
+
// Update state files from revision
|
|
76
|
+
const storyDir = join(bookDir, "story");
|
|
77
|
+
if (reviseOutput.updatedState !== "(状态卡未更新)") {
|
|
78
|
+
await writeFile(join(storyDir, "current_state.md"), reviseOutput.updatedState, "utf-8");
|
|
79
|
+
}
|
|
80
|
+
if (reviseOutput.updatedLedger !== "(账本未更新)") {
|
|
81
|
+
await writeFile(join(storyDir, "particle_ledger.md"), reviseOutput.updatedLedger, "utf-8");
|
|
82
|
+
}
|
|
83
|
+
if (reviseOutput.updatedHooks !== "(伏笔池未更新)") {
|
|
84
|
+
await writeFile(join(storyDir, "pending_hooks.md"), reviseOutput.updatedHooks, "utf-8");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// 4. Save chapter (original or revised)
|
|
90
|
+
const chaptersDir = join(bookDir, "chapters");
|
|
91
|
+
const paddedNum = String(chapterNumber).padStart(4, "0");
|
|
92
|
+
const title = revised ? output.title : output.title;
|
|
93
|
+
const filename = `${paddedNum}_${title.replace(/[/\\?%*:|"<>]/g, "").replace(/\s+/g, "_").slice(0, 50)}.md`;
|
|
94
|
+
await writeFile(join(chaptersDir, filename), `# 第${chapterNumber}章 ${title}\n\n${finalContent}`, "utf-8");
|
|
95
|
+
// Save original state files if not revised
|
|
96
|
+
if (!revised) {
|
|
97
|
+
await writer.saveChapter(bookDir, output);
|
|
98
|
+
}
|
|
99
|
+
// 5. Update chapter index
|
|
100
|
+
const existingIndex = await this.state.loadChapterIndex(bookId);
|
|
101
|
+
const now = new Date().toISOString();
|
|
102
|
+
const newEntry = {
|
|
103
|
+
number: chapterNumber,
|
|
104
|
+
title: output.title,
|
|
105
|
+
status: auditResult.passed ? "ready-for-review" : "audit-failed",
|
|
106
|
+
wordCount: finalWordCount,
|
|
107
|
+
createdAt: now,
|
|
108
|
+
updatedAt: now,
|
|
109
|
+
auditIssues: auditResult.issues.map((i) => `[${i.severity}] ${i.description}`),
|
|
110
|
+
};
|
|
111
|
+
await this.state.saveChapterIndex(bookId, [...existingIndex, newEntry]);
|
|
112
|
+
// 5.5 Snapshot state for rollback support
|
|
113
|
+
await this.state.snapshotState(bookId, chapterNumber);
|
|
114
|
+
// 6. Send notification
|
|
115
|
+
if (this.config.notifyChannels && this.config.notifyChannels.length > 0) {
|
|
116
|
+
const statusEmoji = auditResult.passed ? "✅" : "⚠️";
|
|
117
|
+
await dispatchNotification(this.config.notifyChannels, {
|
|
118
|
+
title: `${statusEmoji} ${book.title} 第${chapterNumber}章`,
|
|
119
|
+
body: [
|
|
120
|
+
`**${output.title}** | ${finalWordCount}字`,
|
|
121
|
+
revised ? "📝 已自动修正" : "",
|
|
122
|
+
`审稿: ${auditResult.passed ? "通过" : "需人工审核"}`,
|
|
123
|
+
...auditResult.issues
|
|
124
|
+
.filter((i) => i.severity !== "info")
|
|
125
|
+
.map((i) => `- [${i.severity}] ${i.description}`),
|
|
126
|
+
]
|
|
127
|
+
.filter(Boolean)
|
|
128
|
+
.join("\n"),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
chapterNumber,
|
|
133
|
+
title: output.title,
|
|
134
|
+
wordCount: finalWordCount,
|
|
135
|
+
auditResult,
|
|
136
|
+
revised,
|
|
137
|
+
status: auditResult.passed ? "approved" : "needs-review",
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/pipeline/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { PipelineConfig } from "./runner.js";
|
|
2
|
+
export interface SchedulerConfig extends PipelineConfig {
|
|
3
|
+
readonly radarCron: string;
|
|
4
|
+
readonly writeCron: string;
|
|
5
|
+
readonly auditCron: string;
|
|
6
|
+
readonly maxConcurrentBooks: number;
|
|
7
|
+
readonly onChapterComplete?: (bookId: string, chapter: number, status: string) => void;
|
|
8
|
+
readonly onError?: (bookId: string, error: Error) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare class Scheduler {
|
|
11
|
+
private readonly pipeline;
|
|
12
|
+
private readonly state;
|
|
13
|
+
private readonly config;
|
|
14
|
+
private tasks;
|
|
15
|
+
private running;
|
|
16
|
+
constructor(config: SchedulerConfig);
|
|
17
|
+
start(): Promise<void>;
|
|
18
|
+
stop(): void;
|
|
19
|
+
get isRunning(): boolean;
|
|
20
|
+
private runWriteCycle;
|
|
21
|
+
private runRadarScan;
|
|
22
|
+
private cronToMs;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=scheduler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/pipeline/scheduler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvF,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC3D;AAQD,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,EAAE,eAAe;IAM7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkC5B,IAAI,IAAI,IAAI;IAQZ,IAAI,SAAS,IAAI,OAAO,CAEvB;YAEa,aAAa;YA2Bb,YAAY;IAQ1B,OAAO,CAAC,QAAQ;CAiBjB"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { PipelineRunner } from "./runner.js";
|
|
2
|
+
import { StateManager } from "../state/manager.js";
|
|
3
|
+
export class Scheduler {
|
|
4
|
+
pipeline;
|
|
5
|
+
state;
|
|
6
|
+
config;
|
|
7
|
+
tasks = [];
|
|
8
|
+
running = false;
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.config = config;
|
|
11
|
+
this.pipeline = new PipelineRunner(config);
|
|
12
|
+
this.state = new StateManager(config.projectRoot);
|
|
13
|
+
}
|
|
14
|
+
async start() {
|
|
15
|
+
if (this.running)
|
|
16
|
+
return;
|
|
17
|
+
this.running = true;
|
|
18
|
+
// Run write cycle immediately on start, then schedule
|
|
19
|
+
await this.runWriteCycle();
|
|
20
|
+
// Schedule recurring write cycle (default: every 2 hours)
|
|
21
|
+
const writeCycleMs = this.cronToMs(this.config.writeCron);
|
|
22
|
+
const writeTask = {
|
|
23
|
+
name: "write-cycle",
|
|
24
|
+
intervalMs: writeCycleMs,
|
|
25
|
+
};
|
|
26
|
+
writeTask.timer = setInterval(() => {
|
|
27
|
+
this.runWriteCycle().catch((e) => {
|
|
28
|
+
this.config.onError?.("scheduler", e);
|
|
29
|
+
});
|
|
30
|
+
}, writeCycleMs);
|
|
31
|
+
this.tasks.push(writeTask);
|
|
32
|
+
// Schedule radar scan (default: daily)
|
|
33
|
+
const radarMs = this.cronToMs(this.config.radarCron);
|
|
34
|
+
const radarTask = {
|
|
35
|
+
name: "radar-scan",
|
|
36
|
+
intervalMs: radarMs,
|
|
37
|
+
};
|
|
38
|
+
radarTask.timer = setInterval(() => {
|
|
39
|
+
this.runRadarScan().catch((e) => {
|
|
40
|
+
this.config.onError?.("radar", e);
|
|
41
|
+
});
|
|
42
|
+
}, radarMs);
|
|
43
|
+
this.tasks.push(radarTask);
|
|
44
|
+
}
|
|
45
|
+
stop() {
|
|
46
|
+
this.running = false;
|
|
47
|
+
for (const task of this.tasks) {
|
|
48
|
+
if (task.timer)
|
|
49
|
+
clearInterval(task.timer);
|
|
50
|
+
}
|
|
51
|
+
this.tasks = [];
|
|
52
|
+
}
|
|
53
|
+
get isRunning() {
|
|
54
|
+
return this.running;
|
|
55
|
+
}
|
|
56
|
+
async runWriteCycle() {
|
|
57
|
+
const bookIds = await this.state.listBooks();
|
|
58
|
+
const activeBooks = [];
|
|
59
|
+
for (const id of bookIds) {
|
|
60
|
+
const config = await this.state.loadBookConfig(id);
|
|
61
|
+
if (config.status === "active" || config.status === "outlining") {
|
|
62
|
+
activeBooks.push({ id, config });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const booksToWrite = activeBooks.slice(0, this.config.maxConcurrentBooks);
|
|
66
|
+
for (const book of booksToWrite) {
|
|
67
|
+
try {
|
|
68
|
+
const result = await this.pipeline.writeNextChapter(book.id);
|
|
69
|
+
this.config.onChapterComplete?.(book.id, result.chapterNumber, result.status);
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
this.config.onError?.(book.id, e);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async runRadarScan() {
|
|
77
|
+
try {
|
|
78
|
+
await this.pipeline.runRadar();
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
this.config.onError?.("radar", e);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
cronToMs(cron) {
|
|
85
|
+
// Simple cron-to-interval mapping for common patterns
|
|
86
|
+
// "0 9 * * *" = daily = 24h
|
|
87
|
+
// "0 14 * * *" = daily = 24h
|
|
88
|
+
// "0 */2 * * *" = every 2h
|
|
89
|
+
const parts = cron.split(" ");
|
|
90
|
+
if (parts.length >= 5) {
|
|
91
|
+
const hour = parts[1];
|
|
92
|
+
if (hour.startsWith("*/")) {
|
|
93
|
+
const interval = parseInt(hour.slice(2), 10);
|
|
94
|
+
return interval * 60 * 60 * 1000;
|
|
95
|
+
}
|
|
96
|
+
// Default: treat as daily
|
|
97
|
+
return 24 * 60 * 60 * 1000;
|
|
98
|
+
}
|
|
99
|
+
return 24 * 60 * 60 * 1000;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=scheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/pipeline/scheduler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { BookConfig } from "../models/book.js";
|
|
2
|
+
import type { ChapterMeta } from "../models/chapter.js";
|
|
3
|
+
export declare class StateManager {
|
|
4
|
+
private readonly projectRoot;
|
|
5
|
+
constructor(projectRoot: string);
|
|
6
|
+
acquireBookLock(bookId: string): Promise<() => Promise<void>>;
|
|
7
|
+
get booksDir(): string;
|
|
8
|
+
bookDir(bookId: string): string;
|
|
9
|
+
loadProjectConfig(): Promise<Record<string, unknown>>;
|
|
10
|
+
saveProjectConfig(config: Record<string, unknown>): Promise<void>;
|
|
11
|
+
loadBookConfig(bookId: string): Promise<BookConfig>;
|
|
12
|
+
saveBookConfig(bookId: string, config: BookConfig): Promise<void>;
|
|
13
|
+
listBooks(): Promise<ReadonlyArray<string>>;
|
|
14
|
+
getNextChapterNumber(bookId: string): Promise<number>;
|
|
15
|
+
loadChapterIndex(bookId: string): Promise<ReadonlyArray<ChapterMeta>>;
|
|
16
|
+
saveChapterIndex(bookId: string, index: ReadonlyArray<ChapterMeta>): Promise<void>;
|
|
17
|
+
snapshotState(bookId: string, chapterNumber: number): Promise<void>;
|
|
18
|
+
restoreState(bookId: string, chapterNumber: number): Promise<boolean>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/state/manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,WAAW;gBAAX,WAAW,EAAE,MAAM;IAE1C,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAsBnE,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAIzB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAMrD,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjE,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAMnD,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAUjE,SAAS,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAmB3C,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAOrD,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IAUrE,gBAAgB,CACpB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,aAAa,CAAC,WAAW,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC;IAUV,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBnE,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAiB5E"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir, readdir, stat, unlink } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
export class StateManager {
|
|
4
|
+
projectRoot;
|
|
5
|
+
constructor(projectRoot) {
|
|
6
|
+
this.projectRoot = projectRoot;
|
|
7
|
+
}
|
|
8
|
+
async acquireBookLock(bookId) {
|
|
9
|
+
const lockPath = join(this.bookDir(bookId), ".write.lock");
|
|
10
|
+
try {
|
|
11
|
+
await stat(lockPath);
|
|
12
|
+
const lockData = await readFile(lockPath, "utf-8");
|
|
13
|
+
throw new Error(`Book "${bookId}" is locked by another process (${lockData}). ` +
|
|
14
|
+
`If this is stale, delete ${lockPath}`);
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
if (e instanceof Error && e.message.includes("is locked"))
|
|
18
|
+
throw e;
|
|
19
|
+
}
|
|
20
|
+
await writeFile(lockPath, `pid:${process.pid} ts:${Date.now()}`, "utf-8");
|
|
21
|
+
return async () => {
|
|
22
|
+
try {
|
|
23
|
+
await unlink(lockPath);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// ignore
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
get booksDir() {
|
|
31
|
+
return join(this.projectRoot, "books");
|
|
32
|
+
}
|
|
33
|
+
bookDir(bookId) {
|
|
34
|
+
return join(this.booksDir, bookId);
|
|
35
|
+
}
|
|
36
|
+
async loadProjectConfig() {
|
|
37
|
+
const configPath = join(this.projectRoot, "inkos.json");
|
|
38
|
+
const raw = await readFile(configPath, "utf-8");
|
|
39
|
+
return JSON.parse(raw);
|
|
40
|
+
}
|
|
41
|
+
async saveProjectConfig(config) {
|
|
42
|
+
const configPath = join(this.projectRoot, "inkos.json");
|
|
43
|
+
await writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
44
|
+
}
|
|
45
|
+
async loadBookConfig(bookId) {
|
|
46
|
+
const configPath = join(this.bookDir(bookId), "book.json");
|
|
47
|
+
const raw = await readFile(configPath, "utf-8");
|
|
48
|
+
return JSON.parse(raw);
|
|
49
|
+
}
|
|
50
|
+
async saveBookConfig(bookId, config) {
|
|
51
|
+
const dir = this.bookDir(bookId);
|
|
52
|
+
await mkdir(dir, { recursive: true });
|
|
53
|
+
await writeFile(join(dir, "book.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
54
|
+
}
|
|
55
|
+
async listBooks() {
|
|
56
|
+
try {
|
|
57
|
+
const entries = await readdir(this.booksDir);
|
|
58
|
+
const bookIds = [];
|
|
59
|
+
for (const entry of entries) {
|
|
60
|
+
const bookJsonPath = join(this.booksDir, entry, "book.json");
|
|
61
|
+
try {
|
|
62
|
+
await stat(bookJsonPath);
|
|
63
|
+
bookIds.push(entry);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// not a book directory
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return bookIds;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async getNextChapterNumber(bookId) {
|
|
76
|
+
const index = await this.loadChapterIndex(bookId);
|
|
77
|
+
if (index.length === 0)
|
|
78
|
+
return 1;
|
|
79
|
+
const maxNum = Math.max(...index.map((ch) => ch.number));
|
|
80
|
+
return maxNum + 1;
|
|
81
|
+
}
|
|
82
|
+
async loadChapterIndex(bookId) {
|
|
83
|
+
const indexPath = join(this.bookDir(bookId), "chapters", "index.json");
|
|
84
|
+
try {
|
|
85
|
+
const raw = await readFile(indexPath, "utf-8");
|
|
86
|
+
return JSON.parse(raw);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async saveChapterIndex(bookId, index) {
|
|
93
|
+
const chaptersDir = join(this.bookDir(bookId), "chapters");
|
|
94
|
+
await mkdir(chaptersDir, { recursive: true });
|
|
95
|
+
await writeFile(join(chaptersDir, "index.json"), JSON.stringify(index, null, 2), "utf-8");
|
|
96
|
+
}
|
|
97
|
+
async snapshotState(bookId, chapterNumber) {
|
|
98
|
+
const storyDir = join(this.bookDir(bookId), "story");
|
|
99
|
+
const snapshotDir = join(storyDir, "snapshots", String(chapterNumber));
|
|
100
|
+
await mkdir(snapshotDir, { recursive: true });
|
|
101
|
+
const files = ["current_state.md", "particle_ledger.md", "pending_hooks.md"];
|
|
102
|
+
await Promise.all(files.map(async (f) => {
|
|
103
|
+
try {
|
|
104
|
+
const content = await readFile(join(storyDir, f), "utf-8");
|
|
105
|
+
await writeFile(join(snapshotDir, f), content, "utf-8");
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// file doesn't exist yet
|
|
109
|
+
}
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
async restoreState(bookId, chapterNumber) {
|
|
113
|
+
const storyDir = join(this.bookDir(bookId), "story");
|
|
114
|
+
const snapshotDir = join(storyDir, "snapshots", String(chapterNumber));
|
|
115
|
+
const files = ["current_state.md", "particle_ledger.md", "pending_hooks.md"];
|
|
116
|
+
try {
|
|
117
|
+
await Promise.all(files.map(async (f) => {
|
|
118
|
+
const content = await readFile(join(snapshotDir, f), "utf-8");
|
|
119
|
+
await writeFile(join(storyDir, f), content, "utf-8");
|
|
120
|
+
}));
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/state/manager.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@actalk/inkos-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "InkOS core: models, agents, pipeline, LLM integration",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": ["dist"],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/Narcooo/inkos.git",
|
|
19
|
+
"directory": "packages/core"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"dev": "tsc --watch",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"typecheck": "tsc --noEmit"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"openai": "^4.80.0",
|
|
29
|
+
"zod": "^3.24.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"typescript": "^5.8.0",
|
|
33
|
+
"vitest": "^3.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|