@actalk/inkos-core 0.3.4 → 0.3.6
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 +21 -0
- package/dist/__tests__/ai-tells.test.d.ts +2 -0
- package/dist/__tests__/ai-tells.test.d.ts.map +1 -0
- package/dist/__tests__/ai-tells.test.js +78 -0
- package/dist/__tests__/ai-tells.test.js.map +1 -0
- package/dist/__tests__/detection-insights.test.d.ts +2 -0
- package/dist/__tests__/detection-insights.test.d.ts.map +1 -0
- package/dist/__tests__/detection-insights.test.js +50 -0
- package/dist/__tests__/detection-insights.test.js.map +1 -0
- package/dist/__tests__/detector.test.d.ts +2 -0
- package/dist/__tests__/detector.test.d.ts.map +1 -0
- package/dist/__tests__/detector.test.js +71 -0
- package/dist/__tests__/detector.test.js.map +1 -0
- package/dist/__tests__/style-analyzer.test.d.ts +2 -0
- package/dist/__tests__/style-analyzer.test.d.ts.map +1 -0
- package/dist/__tests__/style-analyzer.test.js +53 -0
- package/dist/__tests__/style-analyzer.test.js.map +1 -0
- package/dist/__tests__/webhook.test.d.ts +2 -0
- package/dist/__tests__/webhook.test.d.ts.map +1 -0
- package/dist/__tests__/webhook.test.js +62 -0
- package/dist/__tests__/webhook.test.js.map +1 -0
- package/dist/agents/ai-tells.d.ts +24 -0
- package/dist/agents/ai-tells.d.ts.map +1 -0
- package/dist/agents/ai-tells.js +114 -0
- package/dist/agents/ai-tells.js.map +1 -0
- package/dist/agents/architect.d.ts.map +1 -1
- package/dist/agents/architect.js +2 -0
- package/dist/agents/architect.js.map +1 -1
- package/dist/agents/continuity.d.ts.map +1 -1
- package/dist/agents/continuity.js +34 -2
- package/dist/agents/continuity.js.map +1 -1
- package/dist/agents/detection-insights.d.ts +9 -0
- package/dist/agents/detection-insights.d.ts.map +1 -0
- package/dist/agents/detection-insights.js +54 -0
- package/dist/agents/detection-insights.js.map +1 -0
- package/dist/agents/detector.d.ts +17 -0
- package/dist/agents/detector.d.ts.map +1 -0
- package/dist/agents/detector.js +77 -0
- package/dist/agents/detector.js.map +1 -0
- package/dist/agents/reviser.d.ts +1 -1
- package/dist/agents/reviser.d.ts.map +1 -1
- package/dist/agents/reviser.js +1 -0
- package/dist/agents/reviser.js.map +1 -1
- package/dist/agents/style-analyzer.d.ts +11 -0
- package/dist/agents/style-analyzer.d.ts.map +1 -0
- package/dist/agents/style-analyzer.js +81 -0
- package/dist/agents/style-analyzer.js.map +1 -0
- package/dist/agents/writer-prompts.d.ts +1 -1
- package/dist/agents/writer-prompts.d.ts.map +1 -1
- package/dist/agents/writer-prompts.js +42 -2
- package/dist/agents/writer-prompts.js.map +1 -1
- package/dist/agents/writer.d.ts +9 -0
- package/dist/agents/writer.d.ts.map +1 -1
- package/dist/agents/writer.js +98 -5
- package/dist/agents/writer.js.map +1 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/models/chapter.d.ts +9 -0
- package/dist/models/chapter.d.ts.map +1 -1
- package/dist/models/chapter.js +3 -0
- package/dist/models/chapter.js.map +1 -1
- package/dist/models/detection.d.ts +25 -0
- package/dist/models/detection.d.ts.map +1 -0
- package/dist/models/detection.js +2 -0
- package/dist/models/detection.js.map +1 -0
- package/dist/models/project.d.ts +156 -0
- package/dist/models/project.d.ts.map +1 -1
- package/dist/models/project.js +31 -0
- package/dist/models/project.js.map +1 -1
- package/dist/models/style-profile.d.ts +16 -0
- package/dist/models/style-profile.d.ts.map +1 -0
- package/dist/models/style-profile.js +2 -0
- package/dist/models/style-profile.js.map +1 -0
- package/dist/notify/dispatcher.d.ts +3 -0
- package/dist/notify/dispatcher.d.ts.map +1 -1
- package/dist/notify/dispatcher.js +28 -0
- package/dist/notify/dispatcher.js.map +1 -1
- package/dist/notify/webhook.d.ts +15 -0
- package/dist/notify/webhook.d.ts.map +1 -0
- package/dist/notify/webhook.js +28 -0
- package/dist/notify/webhook.js.map +1 -0
- package/dist/pipeline/detection-runner.d.ts +31 -0
- package/dist/pipeline/detection-runner.d.ts.map +1 -0
- package/dist/pipeline/detection-runner.js +109 -0
- package/dist/pipeline/detection-runner.js.map +1 -0
- package/dist/pipeline/runner.d.ts +3 -2
- package/dist/pipeline/runner.d.ts.map +1 -1
- package/dist/pipeline/runner.js +63 -8
- package/dist/pipeline/runner.js.map +1 -1
- package/dist/pipeline/scheduler.d.ts +11 -0
- package/dist/pipeline/scheduler.d.ts.map +1 -1
- package/dist/pipeline/scheduler.js +60 -0
- package/dist/pipeline/scheduler.js.map +1 -1
- package/dist/state/manager.d.ts.map +1 -1
- package/dist/state/manager.js +21 -3
- package/dist/state/manager.js.map +1 -1
- package/package.json +8 -8
package/dist/models/project.js
CHANGED
|
@@ -23,12 +23,33 @@ export const NotifyChannelSchema = z.discriminatedUnion("type", [
|
|
|
23
23
|
type: z.literal("feishu"),
|
|
24
24
|
webhookUrl: z.string().url(),
|
|
25
25
|
}),
|
|
26
|
+
z.object({
|
|
27
|
+
type: z.literal("webhook"),
|
|
28
|
+
url: z.string().url(),
|
|
29
|
+
secret: z.string().optional(),
|
|
30
|
+
events: z.array(z.string()).default([]),
|
|
31
|
+
}),
|
|
26
32
|
]);
|
|
33
|
+
export const DetectionConfigSchema = z.object({
|
|
34
|
+
provider: z.enum(["gptzero", "originality", "custom"]).default("custom"),
|
|
35
|
+
apiUrl: z.string().url(),
|
|
36
|
+
apiKeyEnv: z.string().min(1),
|
|
37
|
+
threshold: z.number().min(0).max(1).default(0.5),
|
|
38
|
+
enabled: z.boolean().default(false),
|
|
39
|
+
autoRewrite: z.boolean().default(false),
|
|
40
|
+
maxRetries: z.number().int().min(1).max(10).default(3),
|
|
41
|
+
});
|
|
42
|
+
export const QualityGatesSchema = z.object({
|
|
43
|
+
maxAuditRetries: z.number().int().min(0).max(10).default(2),
|
|
44
|
+
pauseAfterConsecutiveFailures: z.number().int().min(1).default(3),
|
|
45
|
+
retryTemperatureStep: z.number().min(0).max(0.5).default(0.1),
|
|
46
|
+
});
|
|
27
47
|
export const ProjectConfigSchema = z.object({
|
|
28
48
|
name: z.string().min(1),
|
|
29
49
|
version: z.literal("0.1.0"),
|
|
30
50
|
llm: LLMConfigSchema,
|
|
31
51
|
notify: z.array(NotifyChannelSchema).default([]),
|
|
52
|
+
detection: DetectionConfigSchema.optional(),
|
|
32
53
|
daemon: z.object({
|
|
33
54
|
schedule: z.object({
|
|
34
55
|
radarCron: z.string().default("0 9 * * *"),
|
|
@@ -36,6 +57,11 @@ export const ProjectConfigSchema = z.object({
|
|
|
36
57
|
auditCron: z.string().default("0 17 * * *"),
|
|
37
58
|
}),
|
|
38
59
|
maxConcurrentBooks: z.number().int().min(1).default(3),
|
|
60
|
+
qualityGates: QualityGatesSchema.default({
|
|
61
|
+
maxAuditRetries: 2,
|
|
62
|
+
pauseAfterConsecutiveFailures: 3,
|
|
63
|
+
retryTemperatureStep: 0.1,
|
|
64
|
+
}),
|
|
39
65
|
}).default({
|
|
40
66
|
schedule: {
|
|
41
67
|
radarCron: "0 9 * * *",
|
|
@@ -43,6 +69,11 @@ export const ProjectConfigSchema = z.object({
|
|
|
43
69
|
auditCron: "0 17 * * *",
|
|
44
70
|
},
|
|
45
71
|
maxConcurrentBooks: 3,
|
|
72
|
+
qualityGates: {
|
|
73
|
+
maxAuditRetries: 2,
|
|
74
|
+
pauseAfterConsecutiveFailures: 3,
|
|
75
|
+
retryTemperatureStep: 0.1,
|
|
76
|
+
},
|
|
46
77
|
}),
|
|
47
78
|
});
|
|
48
79
|
//# sourceMappingURL=project.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/models/project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACnD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACzB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IAClD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IAChD,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAClD,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;CACzD,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IAC9D,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;QAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;KAC1B,CAAC;IACF,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;QAC9B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;KAC7B,CAAC;IACF,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;QACzB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;KAC7B,CAAC;CACH,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IAC3B,GAAG,EAAE,eAAe;IACpB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAChD,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC;YACjB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC;YAC1C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC;YAC3C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC;SAC5C,CAAC;QACF,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/models/project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACnD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACzB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IAClD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IAChD,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAClD,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;CACzD,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IAC9D,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;QAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;KAC1B,CAAC;IACF,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;QAC9B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;KAC7B,CAAC;IACF,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;QACzB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;KAC7B,CAAC;IACF,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;QAC1B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;QACrB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC7B,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;KACxC,CAAC;CACH,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IACxE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACxB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IAChD,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IACnC,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IACvC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;CACvD,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3D,6BAA6B,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACjE,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;CAC9D,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IAC3B,GAAG,EAAE,eAAe;IACpB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAChD,SAAS,EAAE,qBAAqB,CAAC,QAAQ,EAAE;IAC3C,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC;YACjB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC;YAC1C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC;YAC3C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC;SAC5C,CAAC;QACF,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,YAAY,EAAE,kBAAkB,CAAC,OAAO,CAAC;YACvC,eAAe,EAAE,CAAC;YAClB,6BAA6B,EAAE,CAAC;YAChC,oBAAoB,EAAE,GAAG;SAC1B,CAAC;KACH,CAAC,CAAC,OAAO,CAAC;QACT,QAAQ,EAAE;YACR,SAAS,EAAE,WAAW;YACtB,SAAS,EAAE,YAAY;YACvB,SAAS,EAAE,YAAY;SACxB;QACD,kBAAkB,EAAE,CAAC;QACrB,YAAY,EAAE;YACZ,eAAe,EAAE,CAAC;YAClB,6BAA6B,EAAE,CAAC;YAChC,oBAAoB,EAAE,GAAG;SAC1B;KACF,CAAC;CACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Style fingerprint profile extracted from reference text. */
|
|
2
|
+
export interface StyleProfile {
|
|
3
|
+
readonly avgSentenceLength: number;
|
|
4
|
+
readonly sentenceLengthStdDev: number;
|
|
5
|
+
readonly avgParagraphLength: number;
|
|
6
|
+
readonly paragraphLengthRange: {
|
|
7
|
+
readonly min: number;
|
|
8
|
+
readonly max: number;
|
|
9
|
+
};
|
|
10
|
+
readonly vocabularyDiversity: number;
|
|
11
|
+
readonly topPatterns: ReadonlyArray<string>;
|
|
12
|
+
readonly rhetoricalFeatures: ReadonlyArray<string>;
|
|
13
|
+
readonly sourceName?: string;
|
|
14
|
+
readonly analyzedAt?: string;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=style-profile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style-profile.d.ts","sourceRoot":"","sources":["../../src/models/style-profile.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,oBAAoB,EAAE;QAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5C,QAAQ,CAAC,kBAAkB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACnD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style-profile.js","sourceRoot":"","sources":["../../src/models/style-profile.ts"],"names":[],"mappings":""}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { NotifyChannel } from "../models/project.js";
|
|
2
|
+
import { type WebhookPayload } from "./webhook.js";
|
|
2
3
|
export interface NotifyMessage {
|
|
3
4
|
readonly title: string;
|
|
4
5
|
readonly body: string;
|
|
5
6
|
}
|
|
6
7
|
export declare function dispatchNotification(channels: ReadonlyArray<NotifyChannel>, message: NotifyMessage): Promise<void>;
|
|
8
|
+
/** Dispatch a structured webhook event to all webhook channels. */
|
|
9
|
+
export declare function dispatchWebhookEvent(channels: ReadonlyArray<NotifyChannel>, payload: WebhookPayload): Promise<void>;
|
|
7
10
|
//# sourceMappingURL=dispatcher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/notify/dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/notify/dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI1D,OAAO,EAAe,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAEhE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,EACtC,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CAgDf;AAED,mEAAmE;AACnE,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,EACtC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CAiBf"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { sendTelegram } from "./telegram.js";
|
|
2
2
|
import { sendFeishu } from "./feishu.js";
|
|
3
3
|
import { sendWechatWork } from "./wechat-work.js";
|
|
4
|
+
import { sendWebhook } from "./webhook.js";
|
|
4
5
|
export async function dispatchNotification(channels, message) {
|
|
5
6
|
const fullText = `**${message.title}**\n\n${message.body}`;
|
|
6
7
|
const tasks = channels.map(async (channel) => {
|
|
@@ -15,6 +16,16 @@ export async function dispatchNotification(channels, message) {
|
|
|
15
16
|
case "wechat-work":
|
|
16
17
|
await sendWechatWork({ webhookUrl: channel.webhookUrl }, fullText);
|
|
17
18
|
break;
|
|
19
|
+
case "webhook":
|
|
20
|
+
// Webhook channels are handled by dispatchWebhookEvent for structured events.
|
|
21
|
+
// For generic text notifications, send as a pipeline-complete event.
|
|
22
|
+
await sendWebhook({ url: channel.url, secret: channel.secret, events: channel.events }, {
|
|
23
|
+
event: "pipeline-complete",
|
|
24
|
+
bookId: "",
|
|
25
|
+
timestamp: new Date().toISOString(),
|
|
26
|
+
data: { title: message.title, body: message.body },
|
|
27
|
+
});
|
|
28
|
+
break;
|
|
18
29
|
}
|
|
19
30
|
}
|
|
20
31
|
catch (e) {
|
|
@@ -24,4 +35,21 @@ export async function dispatchNotification(channels, message) {
|
|
|
24
35
|
});
|
|
25
36
|
await Promise.all(tasks);
|
|
26
37
|
}
|
|
38
|
+
/** Dispatch a structured webhook event to all webhook channels. */
|
|
39
|
+
export async function dispatchWebhookEvent(channels, payload) {
|
|
40
|
+
const webhookChannels = channels.filter((ch) => ch.type === "webhook");
|
|
41
|
+
if (webhookChannels.length === 0)
|
|
42
|
+
return;
|
|
43
|
+
const tasks = webhookChannels.map(async (channel) => {
|
|
44
|
+
if (channel.type !== "webhook")
|
|
45
|
+
return;
|
|
46
|
+
try {
|
|
47
|
+
await sendWebhook({ url: channel.url, secret: channel.secret, events: channel.events }, payload);
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
process.stderr.write(`[webhook] ${channel.url} failed: ${e}\n`);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
await Promise.all(tasks);
|
|
54
|
+
}
|
|
27
55
|
//# sourceMappingURL=dispatcher.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../../src/notify/dispatcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../../src/notify/dispatcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface WebhookConfig {
|
|
2
|
+
readonly url: string;
|
|
3
|
+
readonly secret?: string;
|
|
4
|
+
readonly events?: ReadonlyArray<string>;
|
|
5
|
+
}
|
|
6
|
+
export type WebhookEvent = "chapter-complete" | "audit-passed" | "audit-failed" | "revision-complete" | "pipeline-complete" | "pipeline-error";
|
|
7
|
+
export interface WebhookPayload {
|
|
8
|
+
readonly event: WebhookEvent;
|
|
9
|
+
readonly bookId: string;
|
|
10
|
+
readonly chapterNumber?: number;
|
|
11
|
+
readonly timestamp: string;
|
|
12
|
+
readonly data?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
export declare function sendWebhook(config: WebhookConfig, payload: WebhookPayload): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=webhook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../src/notify/webhook.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACzC;AAED,MAAM,MAAM,YAAY,GACpB,kBAAkB,GAClB,cAAc,GACd,cAAc,GACd,mBAAmB,GACnB,mBAAmB,GACnB,gBAAgB,CAAC;AAErB,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CA6Bf"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createHmac } from "node:crypto";
|
|
2
|
+
export async function sendWebhook(config, payload) {
|
|
3
|
+
// Filter by subscribed events
|
|
4
|
+
if (config.events && config.events.length > 0 && !config.events.includes(payload.event)) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
const body = JSON.stringify(payload);
|
|
8
|
+
const headers = {
|
|
9
|
+
"Content-Type": "application/json",
|
|
10
|
+
};
|
|
11
|
+
// HMAC-SHA256 signature if secret is configured
|
|
12
|
+
if (config.secret) {
|
|
13
|
+
const signature = createHmac("sha256", config.secret)
|
|
14
|
+
.update(body)
|
|
15
|
+
.digest("hex");
|
|
16
|
+
headers["X-InkOS-Signature"] = `sha256=${signature}`;
|
|
17
|
+
}
|
|
18
|
+
const response = await fetch(config.url, {
|
|
19
|
+
method: "POST",
|
|
20
|
+
headers,
|
|
21
|
+
body,
|
|
22
|
+
});
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
const responseBody = await response.text();
|
|
25
|
+
throw new Error(`Webhook POST to ${config.url} failed: ${response.status} ${responseBody}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/notify/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAwBzC,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAqB,EACrB,OAAuB;IAEvB,8BAA8B;IAC9B,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxF,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;KACnC,CAAC;IAEF,gDAAgD;IAChD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC;aAClD,MAAM,CAAC,IAAI,CAAC;aACZ,MAAM,CAAC,KAAK,CAAC,CAAC;QACjB,OAAO,CAAC,mBAAmB,CAAC,GAAG,UAAU,SAAS,EAAE,CAAC;IACvD,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE;QACvC,MAAM,EAAE,MAAM;QACd,OAAO;QACP,IAAI;KACL,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,GAAG,YAAY,QAAQ,CAAC,MAAM,IAAI,YAAY,EAAE,CAAC,CAAC;IAC9F,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detection pipeline runner — handles detection, auto-rewrite loop, and history tracking.
|
|
3
|
+
* Extracted from runner.ts to keep runner under 800 lines.
|
|
4
|
+
*/
|
|
5
|
+
import type { DetectionConfig } from "../models/project.js";
|
|
6
|
+
import type { DetectionHistoryEntry } from "../models/detection.js";
|
|
7
|
+
import type { AgentContext } from "../agents/base.js";
|
|
8
|
+
import { type DetectionResult } from "../agents/detector.js";
|
|
9
|
+
export interface DetectChapterResult {
|
|
10
|
+
readonly chapterNumber: number;
|
|
11
|
+
readonly detection: DetectionResult;
|
|
12
|
+
readonly passed: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface DetectAndRewriteResult {
|
|
15
|
+
readonly chapterNumber: number;
|
|
16
|
+
readonly originalScore: number;
|
|
17
|
+
readonly finalScore: number;
|
|
18
|
+
readonly attempts: number;
|
|
19
|
+
readonly passed: boolean;
|
|
20
|
+
readonly finalContent: string;
|
|
21
|
+
}
|
|
22
|
+
/** Run detection on a single chapter's content. */
|
|
23
|
+
export declare function detectChapter(config: DetectionConfig, content: string, chapterNumber: number): Promise<DetectChapterResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Detect-and-rewrite loop: detect → revise in anti-detect mode → re-detect,
|
|
26
|
+
* until score passes threshold or max retries reached.
|
|
27
|
+
*/
|
|
28
|
+
export declare function detectAndRewrite(config: DetectionConfig, ctx: AgentContext, bookDir: string, content: string, chapterNumber: number, genre?: string): Promise<DetectAndRewriteResult>;
|
|
29
|
+
/** Load detection history from disk. */
|
|
30
|
+
export declare function loadDetectionHistory(bookDir: string): Promise<ReadonlyArray<DetectionHistoryEntry>>;
|
|
31
|
+
//# sourceMappingURL=detection-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detection-runner.d.ts","sourceRoot":"","sources":["../../src/pipeline/detection-runner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAK9E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,mDAAmD;AACnD,wBAAsB,aAAa,CACjC,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,mBAAmB,CAAC,CAO9B;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,eAAe,EACvB,GAAG,EAAE,YAAY,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,sBAAsB,CAAC,CA2EjC;AAuBD,wCAAwC;AACxC,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC,CAQ/C"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detection pipeline runner — handles detection, auto-rewrite loop, and history tracking.
|
|
3
|
+
* Extracted from runner.ts to keep runner under 800 lines.
|
|
4
|
+
*/
|
|
5
|
+
import { detectAIContent } from "../agents/detector.js";
|
|
6
|
+
import { ReviserAgent } from "../agents/reviser.js";
|
|
7
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
/** Run detection on a single chapter's content. */
|
|
10
|
+
export async function detectChapter(config, content, chapterNumber) {
|
|
11
|
+
const detection = await detectAIContent(config, content);
|
|
12
|
+
return {
|
|
13
|
+
chapterNumber,
|
|
14
|
+
detection,
|
|
15
|
+
passed: detection.score <= config.threshold,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Detect-and-rewrite loop: detect → revise in anti-detect mode → re-detect,
|
|
20
|
+
* until score passes threshold or max retries reached.
|
|
21
|
+
*/
|
|
22
|
+
export async function detectAndRewrite(config, ctx, bookDir, content, chapterNumber, genre) {
|
|
23
|
+
const maxRetries = config.maxRetries;
|
|
24
|
+
let currentContent = content;
|
|
25
|
+
const firstDetection = await detectAIContent(config, currentContent);
|
|
26
|
+
const originalScore = firstDetection.score;
|
|
27
|
+
if (firstDetection.score <= config.threshold) {
|
|
28
|
+
await recordHistory(bookDir, {
|
|
29
|
+
chapterNumber,
|
|
30
|
+
timestamp: firstDetection.detectedAt,
|
|
31
|
+
provider: firstDetection.provider,
|
|
32
|
+
score: firstDetection.score,
|
|
33
|
+
action: "detect",
|
|
34
|
+
attempt: 0,
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
chapterNumber,
|
|
38
|
+
originalScore,
|
|
39
|
+
finalScore: firstDetection.score,
|
|
40
|
+
attempts: 0,
|
|
41
|
+
passed: true,
|
|
42
|
+
finalContent: currentContent,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
let finalScore = firstDetection.score;
|
|
46
|
+
let attempts = 0;
|
|
47
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
48
|
+
attempts = i + 1;
|
|
49
|
+
// Rewrite in anti-detect mode
|
|
50
|
+
const reviser = new ReviserAgent(ctx);
|
|
51
|
+
const reviseOutput = await reviser.reviseChapter(bookDir, currentContent, chapterNumber, [{
|
|
52
|
+
severity: "warning",
|
|
53
|
+
category: "AIGC检测",
|
|
54
|
+
description: `AI检测分数 ${finalScore.toFixed(2)} 超过阈值 ${config.threshold}`,
|
|
55
|
+
suggestion: "降低AI生成痕迹:增加段落长度差异、减少套话、用口语化表达替代书面语",
|
|
56
|
+
}], "anti-detect", genre);
|
|
57
|
+
if (reviseOutput.revisedContent.length === 0)
|
|
58
|
+
break;
|
|
59
|
+
currentContent = reviseOutput.revisedContent;
|
|
60
|
+
// Re-detect
|
|
61
|
+
const reDetection = await detectAIContent(config, currentContent);
|
|
62
|
+
finalScore = reDetection.score;
|
|
63
|
+
await recordHistory(bookDir, {
|
|
64
|
+
chapterNumber,
|
|
65
|
+
timestamp: reDetection.detectedAt,
|
|
66
|
+
provider: reDetection.provider,
|
|
67
|
+
score: reDetection.score,
|
|
68
|
+
action: "rewrite",
|
|
69
|
+
attempt: attempts,
|
|
70
|
+
});
|
|
71
|
+
if (finalScore <= config.threshold)
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
chapterNumber,
|
|
76
|
+
originalScore,
|
|
77
|
+
finalScore,
|
|
78
|
+
attempts,
|
|
79
|
+
passed: finalScore <= config.threshold,
|
|
80
|
+
finalContent: currentContent,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** Append an entry to detection_history.json. */
|
|
84
|
+
async function recordHistory(bookDir, entry) {
|
|
85
|
+
const historyPath = join(bookDir, "story", "detection_history.json");
|
|
86
|
+
let history = [];
|
|
87
|
+
try {
|
|
88
|
+
const raw = await readFile(historyPath, "utf-8");
|
|
89
|
+
history = JSON.parse(raw);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// File doesn't exist yet
|
|
93
|
+
}
|
|
94
|
+
history.push(entry);
|
|
95
|
+
await mkdir(join(bookDir, "story"), { recursive: true });
|
|
96
|
+
await writeFile(historyPath, JSON.stringify(history, null, 2), "utf-8");
|
|
97
|
+
}
|
|
98
|
+
/** Load detection history from disk. */
|
|
99
|
+
export async function loadDetectionHistory(bookDir) {
|
|
100
|
+
const historyPath = join(bookDir, "story", "detection_history.json");
|
|
101
|
+
try {
|
|
102
|
+
const raw = await readFile(historyPath, "utf-8");
|
|
103
|
+
return JSON.parse(raw);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=detection-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detection-runner.js","sourceRoot":"","sources":["../../src/pipeline/detection-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -61,7 +61,7 @@ export declare class PipelineRunner {
|
|
|
61
61
|
runRadar(): Promise<RadarResult>;
|
|
62
62
|
initBook(book: BookConfig): Promise<void>;
|
|
63
63
|
/** Write a single draft chapter. Saves chapter file + truth files + index + snapshot. */
|
|
64
|
-
writeDraft(bookId: string, context?: string): Promise<DraftResult>;
|
|
64
|
+
writeDraft(bookId: string, context?: string, wordCount?: number): Promise<DraftResult>;
|
|
65
65
|
/** Audit the latest (or specified) chapter. Read-only, no lock needed. */
|
|
66
66
|
auditDraft(bookId: string, chapterNumber?: number): Promise<AuditResult & {
|
|
67
67
|
readonly chapterNumber: number;
|
|
@@ -72,8 +72,9 @@ export declare class PipelineRunner {
|
|
|
72
72
|
readTruthFiles(bookId: string): Promise<TruthFiles>;
|
|
73
73
|
/** Get book status overview. */
|
|
74
74
|
getBookStatus(bookId: string): Promise<BookStatusInfo>;
|
|
75
|
-
writeNextChapter(bookId: string): Promise<ChapterPipelineResult>;
|
|
75
|
+
writeNextChapter(bookId: string, wordCount?: number): Promise<ChapterPipelineResult>;
|
|
76
76
|
private _writeNextChapterLocked;
|
|
77
|
+
private emitWebhook;
|
|
77
78
|
private readChapterContent;
|
|
78
79
|
}
|
|
79
80
|
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/pipeline/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAK1D,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAErE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/pipeline/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/pipeline/runner.js
CHANGED
|
@@ -4,8 +4,9 @@ import { ContinuityAuditor } from "../agents/continuity.js";
|
|
|
4
4
|
import { ReviserAgent } from "../agents/reviser.js";
|
|
5
5
|
import { RadarAgent } from "../agents/radar.js";
|
|
6
6
|
import { readGenreProfile } from "../agents/rules-reader.js";
|
|
7
|
+
import { analyzeAITells } from "../agents/ai-tells.js";
|
|
7
8
|
import { StateManager } from "../state/manager.js";
|
|
8
|
-
import { dispatchNotification } from "../notify/dispatcher.js";
|
|
9
|
+
import { dispatchNotification, dispatchWebhookEvent } from "../notify/dispatcher.js";
|
|
9
10
|
import { readFile, readdir, writeFile } from "node:fs/promises";
|
|
10
11
|
import { join } from "node:path";
|
|
11
12
|
export class PipelineRunner {
|
|
@@ -44,7 +45,7 @@ export class PipelineRunner {
|
|
|
44
45
|
await this.state.saveChapterIndex(book.id, []);
|
|
45
46
|
}
|
|
46
47
|
/** Write a single draft chapter. Saves chapter file + truth files + index + snapshot. */
|
|
47
|
-
async writeDraft(bookId, context) {
|
|
48
|
+
async writeDraft(bookId, context, wordCount) {
|
|
48
49
|
const releaseLock = await this.state.acquireBookLock(bookId);
|
|
49
50
|
try {
|
|
50
51
|
const book = await this.state.loadBookConfig(bookId);
|
|
@@ -57,6 +58,7 @@ export class PipelineRunner {
|
|
|
57
58
|
bookDir,
|
|
58
59
|
chapterNumber,
|
|
59
60
|
externalContext: context ?? this.config.externalContext,
|
|
61
|
+
...(wordCount ? { wordCountOverride: wordCount } : {}),
|
|
60
62
|
});
|
|
61
63
|
// Save chapter file
|
|
62
64
|
const chaptersDir = join(bookDir, "chapters");
|
|
@@ -67,6 +69,7 @@ export class PipelineRunner {
|
|
|
67
69
|
await writeFile(filePath, `# 第${chapterNumber}章 ${output.title}\n\n${output.content}`, "utf-8");
|
|
68
70
|
// Save truth files
|
|
69
71
|
await writer.saveChapter(bookDir, output, gp.numericalSystem);
|
|
72
|
+
await writer.saveNewTruthFiles(bookDir, output);
|
|
70
73
|
// Update index
|
|
71
74
|
const existingIndex = await this.state.loadChapterIndex(bookId);
|
|
72
75
|
const now = new Date().toISOString();
|
|
@@ -82,6 +85,10 @@ export class PipelineRunner {
|
|
|
82
85
|
await this.state.saveChapterIndex(bookId, [...existingIndex, newEntry]);
|
|
83
86
|
// Snapshot
|
|
84
87
|
await this.state.snapshotState(bookId, chapterNumber);
|
|
88
|
+
await this.emitWebhook("chapter-complete", bookId, chapterNumber, {
|
|
89
|
+
title: output.title,
|
|
90
|
+
wordCount: output.wordCount,
|
|
91
|
+
});
|
|
85
92
|
return { chapterNumber, title: output.title, wordCount: output.wordCount, filePath };
|
|
86
93
|
}
|
|
87
94
|
finally {
|
|
@@ -98,7 +105,18 @@ export class PipelineRunner {
|
|
|
98
105
|
}
|
|
99
106
|
const content = await this.readChapterContent(bookDir, targetChapter);
|
|
100
107
|
const auditor = new ContinuityAuditor(this.agentCtx(bookId));
|
|
101
|
-
const
|
|
108
|
+
const llmResult = await auditor.auditChapter(bookDir, content, targetChapter, book.genre);
|
|
109
|
+
// Merge rule-based AI-tell detection
|
|
110
|
+
const aiTells = analyzeAITells(content);
|
|
111
|
+
const mergedIssues = [
|
|
112
|
+
...llmResult.issues,
|
|
113
|
+
...aiTells.issues,
|
|
114
|
+
];
|
|
115
|
+
const result = {
|
|
116
|
+
passed: llmResult.passed,
|
|
117
|
+
issues: mergedIssues,
|
|
118
|
+
summary: llmResult.summary,
|
|
119
|
+
};
|
|
102
120
|
// Update index with audit result
|
|
103
121
|
const index = await this.state.loadChapterIndex(bookId);
|
|
104
122
|
const updated = index.map((ch) => ch.number === targetChapter
|
|
@@ -110,6 +128,7 @@ export class PipelineRunner {
|
|
|
110
128
|
}
|
|
111
129
|
: ch);
|
|
112
130
|
await this.state.saveChapterIndex(bookId, updated);
|
|
131
|
+
await this.emitWebhook(result.passed ? "audit-passed" : "audit-failed", bookId, targetChapter, { summary: result.summary, issueCount: result.issues.length });
|
|
113
132
|
return { ...result, chapterNumber: targetChapter };
|
|
114
133
|
}
|
|
115
134
|
/** Revise the latest (or specified) chapter based on audit issues. */
|
|
@@ -172,6 +191,10 @@ export class PipelineRunner {
|
|
|
172
191
|
await this.state.saveChapterIndex(bookId, updatedIndex);
|
|
173
192
|
// Re-snapshot
|
|
174
193
|
await this.state.snapshotState(bookId, targetChapter);
|
|
194
|
+
await this.emitWebhook("revision-complete", bookId, targetChapter, {
|
|
195
|
+
wordCount: reviseOutput.wordCount,
|
|
196
|
+
fixedCount: reviseOutput.fixedIssues.length,
|
|
197
|
+
});
|
|
175
198
|
return {
|
|
176
199
|
chapterNumber: targetChapter,
|
|
177
200
|
wordCount: reviseOutput.wordCount,
|
|
@@ -225,16 +248,16 @@ export class PipelineRunner {
|
|
|
225
248
|
// ---------------------------------------------------------------------------
|
|
226
249
|
// Full pipeline (convenience — runs draft + audit + revise in one shot)
|
|
227
250
|
// ---------------------------------------------------------------------------
|
|
228
|
-
async writeNextChapter(bookId) {
|
|
251
|
+
async writeNextChapter(bookId, wordCount) {
|
|
229
252
|
const releaseLock = await this.state.acquireBookLock(bookId);
|
|
230
253
|
try {
|
|
231
|
-
return await this._writeNextChapterLocked(bookId);
|
|
254
|
+
return await this._writeNextChapterLocked(bookId, wordCount);
|
|
232
255
|
}
|
|
233
256
|
finally {
|
|
234
257
|
await releaseLock();
|
|
235
258
|
}
|
|
236
259
|
}
|
|
237
|
-
async _writeNextChapterLocked(bookId) {
|
|
260
|
+
async _writeNextChapterLocked(bookId, wordCount) {
|
|
238
261
|
const book = await this.state.loadBookConfig(bookId);
|
|
239
262
|
const bookDir = this.state.bookDir(bookId);
|
|
240
263
|
const chapterNumber = await this.state.getNextChapterNumber(bookId);
|
|
@@ -246,10 +269,17 @@ export class PipelineRunner {
|
|
|
246
269
|
bookDir,
|
|
247
270
|
chapterNumber,
|
|
248
271
|
externalContext: this.config.externalContext,
|
|
272
|
+
...(wordCount ? { wordCountOverride: wordCount } : {}),
|
|
249
273
|
});
|
|
250
274
|
// 2. Audit chapter
|
|
251
275
|
const auditor = new ContinuityAuditor(this.agentCtx(bookId));
|
|
252
|
-
|
|
276
|
+
const llmAudit = await auditor.auditChapter(bookDir, output.content, chapterNumber, book.genre);
|
|
277
|
+
const aiTellsResult = analyzeAITells(output.content);
|
|
278
|
+
let auditResult = {
|
|
279
|
+
passed: llmAudit.passed,
|
|
280
|
+
issues: [...llmAudit.issues, ...aiTellsResult.issues],
|
|
281
|
+
summary: llmAudit.summary,
|
|
282
|
+
};
|
|
253
283
|
let finalContent = output.content;
|
|
254
284
|
let finalWordCount = output.wordCount;
|
|
255
285
|
let revised = false;
|
|
@@ -264,7 +294,13 @@ export class PipelineRunner {
|
|
|
264
294
|
finalWordCount = reviseOutput.wordCount;
|
|
265
295
|
revised = true;
|
|
266
296
|
// Re-audit the revised content
|
|
267
|
-
|
|
297
|
+
const reAudit = await auditor.auditChapter(bookDir, finalContent, chapterNumber, book.genre);
|
|
298
|
+
const reAITells = analyzeAITells(finalContent);
|
|
299
|
+
auditResult = {
|
|
300
|
+
passed: reAudit.passed,
|
|
301
|
+
issues: [...reAudit.issues, ...reAITells.issues],
|
|
302
|
+
summary: reAudit.summary,
|
|
303
|
+
};
|
|
268
304
|
// Update state files from revision
|
|
269
305
|
const storyDir = join(bookDir, "story");
|
|
270
306
|
if (reviseOutput.updatedState !== "(状态卡未更新)") {
|
|
@@ -289,6 +325,8 @@ export class PipelineRunner {
|
|
|
289
325
|
if (!revised) {
|
|
290
326
|
await writer.saveChapter(bookDir, output, gp.numericalSystem);
|
|
291
327
|
}
|
|
328
|
+
// Save new truth files (summaries, subplots, emotional arcs, character matrix)
|
|
329
|
+
await writer.saveNewTruthFiles(bookDir, output);
|
|
292
330
|
// 5. Update chapter index
|
|
293
331
|
const existingIndex = await this.state.loadChapterIndex(bookId);
|
|
294
332
|
const now = new Date().toISOString();
|
|
@@ -321,6 +359,12 @@ export class PipelineRunner {
|
|
|
321
359
|
.join("\n"),
|
|
322
360
|
});
|
|
323
361
|
}
|
|
362
|
+
await this.emitWebhook("pipeline-complete", bookId, chapterNumber, {
|
|
363
|
+
title: output.title,
|
|
364
|
+
wordCount: finalWordCount,
|
|
365
|
+
passed: auditResult.passed,
|
|
366
|
+
revised,
|
|
367
|
+
});
|
|
324
368
|
return {
|
|
325
369
|
chapterNumber,
|
|
326
370
|
title: output.title,
|
|
@@ -333,6 +377,17 @@ export class PipelineRunner {
|
|
|
333
377
|
// ---------------------------------------------------------------------------
|
|
334
378
|
// Helpers
|
|
335
379
|
// ---------------------------------------------------------------------------
|
|
380
|
+
async emitWebhook(event, bookId, chapterNumber, data) {
|
|
381
|
+
if (!this.config.notifyChannels || this.config.notifyChannels.length === 0)
|
|
382
|
+
return;
|
|
383
|
+
await dispatchWebhookEvent(this.config.notifyChannels, {
|
|
384
|
+
event,
|
|
385
|
+
bookId,
|
|
386
|
+
chapterNumber,
|
|
387
|
+
timestamp: new Date().toISOString(),
|
|
388
|
+
data,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
336
391
|
async readChapterContent(bookDir, chapterNumber) {
|
|
337
392
|
const chaptersDir = join(bookDir, "chapters");
|
|
338
393
|
const files = await readdir(chaptersDir);
|