@riotprompt/riotdoc 1.0.1-dev.0 → 1.0.4
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/.playwright-mcp/riotplan-cli-step.png +0 -0
- package/.playwright-mcp/riotplan-core-concepts.png +0 -0
- package/.playwright-mcp/riotplan-homepage.png +0 -0
- package/.playwright-mcp/riotplan-mcp-overview.png +0 -0
- package/.playwright-mcp/riotplan-mcp-tools.png +0 -0
- package/README.md +111 -8
- package/dist/__vite-browser-external-2Ng8QIWW.js +5 -0
- package/dist/__vite-browser-external-2Ng8QIWW.js.map +1 -0
- package/dist/cli.js +4 -116
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +152 -57
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/loader-Cvfo7vBn.js +153 -0
- package/dist/loader-Cvfo7vBn.js.map +1 -0
- package/dist/loader-DJHV70rz.js +389 -0
- package/dist/loader-DJHV70rz.js.map +1 -0
- package/dist/mcp-server.d.ts +19 -0
- package/dist/mcp-server.js +1109 -0
- package/dist/mcp-server.js.map +1 -0
- package/package.json +18 -11
- package/templates/blog-post-template.md +367 -0
- package/templates/blog-post-validation.md +278 -0
- package/templates/email-template.md +353 -0
- package/templates/podcast-script-template.md +496 -0
- package/templates/project-plan-template.md +513 -0
- package/templates/research-paper-template.md +497 -0
- package/dist/__vite-browser-external-l0sNRNKZ.js +0 -2
- package/dist/__vite-browser-external-l0sNRNKZ.js.map +0 -1
- package/dist/loader-B7ZeTPQg.js +0 -6358
- package/dist/loader-B7ZeTPQg.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,64 @@ export declare type AssistanceLevel = "generate" | "expand" | "revise" | "cleanu
|
|
|
10
10
|
*/
|
|
11
11
|
export declare function buildVoicePrompt(voice: VoiceConfig): string;
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Checkpoint created event
|
|
15
|
+
*/
|
|
16
|
+
export declare interface CheckpointCreatedEvent extends TimelineEvent {
|
|
17
|
+
type: "checkpoint_created";
|
|
18
|
+
data: {
|
|
19
|
+
/** Checkpoint name (kebab-case) */
|
|
20
|
+
name: string;
|
|
21
|
+
/** Description of checkpoint */
|
|
22
|
+
message: string;
|
|
23
|
+
/** Path to checkpoint snapshot (relative) */
|
|
24
|
+
snapshotPath?: string;
|
|
25
|
+
/** Path to prompt context (relative) */
|
|
26
|
+
promptPath?: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Checkpoint metadata structure
|
|
32
|
+
*/
|
|
33
|
+
export declare interface CheckpointMetadata {
|
|
34
|
+
/** Checkpoint name */
|
|
35
|
+
name: string;
|
|
36
|
+
/** When created (ISO 8601) */
|
|
37
|
+
timestamp: string;
|
|
38
|
+
/** User-provided description */
|
|
39
|
+
message: string;
|
|
40
|
+
/** Current status */
|
|
41
|
+
status: string;
|
|
42
|
+
/** Snapshot of document files */
|
|
43
|
+
snapshot: {
|
|
44
|
+
timestamp: string;
|
|
45
|
+
config?: FileSnapshot;
|
|
46
|
+
outline?: FileSnapshot;
|
|
47
|
+
currentDraft?: FileSnapshot;
|
|
48
|
+
};
|
|
49
|
+
/** Context information */
|
|
50
|
+
context: {
|
|
51
|
+
/** List of .md files at checkpoint */
|
|
52
|
+
filesChanged: string[];
|
|
53
|
+
/** Timeline events since last checkpoint */
|
|
54
|
+
eventsSinceLastCheckpoint: number;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Checkpoint restored event
|
|
60
|
+
*/
|
|
61
|
+
export declare interface CheckpointRestoredEvent extends TimelineEvent {
|
|
62
|
+
type: "checkpoint_restored";
|
|
63
|
+
data: {
|
|
64
|
+
/** Name of restored checkpoint */
|
|
65
|
+
checkpoint: string;
|
|
66
|
+
/** Timestamp of original checkpoint */
|
|
67
|
+
restoredFrom: string;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
13
71
|
/**
|
|
14
72
|
* Create a new RiotDoc workspace
|
|
15
73
|
*/
|
|
@@ -61,6 +119,12 @@ export declare interface DocumentConfig {
|
|
|
61
119
|
type: DocumentType;
|
|
62
120
|
/** Current status */
|
|
63
121
|
status: DocumentStatus;
|
|
122
|
+
/** Current version (e.g., "0.1", "1.0") */
|
|
123
|
+
version: string;
|
|
124
|
+
/** Whether document is published (v1.0+) or draft (v0.x) */
|
|
125
|
+
published: boolean;
|
|
126
|
+
/** Version history */
|
|
127
|
+
versionHistory: VersionHistoryEntry[];
|
|
64
128
|
/** Creation timestamp */
|
|
65
129
|
createdAt: Date;
|
|
66
130
|
/** Last modified timestamp */
|
|
@@ -76,34 +140,27 @@ export declare interface DocumentConfig {
|
|
|
76
140
|
export declare const DocumentConfigSchema: z.ZodObject<{
|
|
77
141
|
id: z.ZodString;
|
|
78
142
|
title: z.ZodString;
|
|
79
|
-
type: z.ZodEnum<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
143
|
+
type: z.ZodEnum<{
|
|
144
|
+
"blog-post": "blog-post";
|
|
145
|
+
"podcast-script": "podcast-script";
|
|
146
|
+
"technical-doc": "technical-doc";
|
|
147
|
+
newsletter: "newsletter";
|
|
148
|
+
custom: "custom";
|
|
149
|
+
}>;
|
|
150
|
+
status: z.ZodEnum<{
|
|
151
|
+
idea: "idea";
|
|
152
|
+
outlined: "outlined";
|
|
153
|
+
drafting: "drafting";
|
|
154
|
+
revising: "revising";
|
|
155
|
+
final: "final";
|
|
156
|
+
exported: "exported";
|
|
157
|
+
}>;
|
|
158
|
+
createdAt: z.ZodCoercedDate<unknown>;
|
|
159
|
+
updatedAt: z.ZodCoercedDate<unknown>;
|
|
83
160
|
targetWordCount: z.ZodOptional<z.ZodNumber>;
|
|
84
161
|
audience: z.ZodOptional<z.ZodString>;
|
|
85
162
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
86
|
-
},
|
|
87
|
-
id: string;
|
|
88
|
-
title: string;
|
|
89
|
-
type: "blog-post" | "podcast-script" | "technical-doc" | "newsletter" | "custom";
|
|
90
|
-
status: "idea" | "outlined" | "drafting" | "revising" | "final" | "exported";
|
|
91
|
-
createdAt: Date;
|
|
92
|
-
updatedAt: Date;
|
|
93
|
-
targetWordCount?: number | undefined;
|
|
94
|
-
audience?: string | undefined;
|
|
95
|
-
metadata?: Record<string, unknown> | undefined;
|
|
96
|
-
}, {
|
|
97
|
-
id: string;
|
|
98
|
-
title: string;
|
|
99
|
-
type: "blog-post" | "podcast-script" | "technical-doc" | "newsletter" | "custom";
|
|
100
|
-
status: "idea" | "outlined" | "drafting" | "revising" | "final" | "exported";
|
|
101
|
-
createdAt: Date;
|
|
102
|
-
updatedAt: Date;
|
|
103
|
-
targetWordCount?: number | undefined;
|
|
104
|
-
audience?: string | undefined;
|
|
105
|
-
metadata?: Record<string, unknown> | undefined;
|
|
106
|
-
}>;
|
|
163
|
+
}, z.core.$strip>;
|
|
107
164
|
|
|
108
165
|
/**
|
|
109
166
|
* Document objectives
|
|
@@ -123,23 +180,11 @@ export declare interface DocumentObjectives {
|
|
|
123
180
|
|
|
124
181
|
export declare const DocumentObjectivesSchema: z.ZodObject<{
|
|
125
182
|
primaryGoal: z.ZodString;
|
|
126
|
-
secondaryGoals: z.ZodArray<z.ZodString
|
|
183
|
+
secondaryGoals: z.ZodArray<z.ZodString>;
|
|
127
184
|
callToAction: z.ZodOptional<z.ZodString>;
|
|
128
|
-
keyTakeaways: z.ZodArray<z.ZodString
|
|
185
|
+
keyTakeaways: z.ZodArray<z.ZodString>;
|
|
129
186
|
emotionalArc: z.ZodOptional<z.ZodString>;
|
|
130
|
-
},
|
|
131
|
-
primaryGoal: string;
|
|
132
|
-
secondaryGoals: string[];
|
|
133
|
-
keyTakeaways: string[];
|
|
134
|
-
callToAction?: string | undefined;
|
|
135
|
-
emotionalArc?: string | undefined;
|
|
136
|
-
}, {
|
|
137
|
-
primaryGoal: string;
|
|
138
|
-
secondaryGoals: string[];
|
|
139
|
-
keyTakeaways: string[];
|
|
140
|
-
callToAction?: string | undefined;
|
|
141
|
-
emotionalArc?: string | undefined;
|
|
142
|
-
}>;
|
|
187
|
+
}, z.core.$strip>;
|
|
143
188
|
|
|
144
189
|
export declare interface DocumentStats {
|
|
145
190
|
wordCount: number;
|
|
@@ -195,6 +240,16 @@ export declare interface EvidenceItem {
|
|
|
195
240
|
incorporatedIn?: string;
|
|
196
241
|
}
|
|
197
242
|
|
|
243
|
+
/**
|
|
244
|
+
* File snapshot in checkpoint
|
|
245
|
+
*/
|
|
246
|
+
export declare interface FileSnapshot {
|
|
247
|
+
/** Whether file exists */
|
|
248
|
+
exists: boolean;
|
|
249
|
+
/** File content (if exists) */
|
|
250
|
+
content?: string;
|
|
251
|
+
}
|
|
252
|
+
|
|
198
253
|
/**
|
|
199
254
|
* Format style validation result for terminal
|
|
200
255
|
*/
|
|
@@ -215,6 +270,23 @@ export declare function loadGlossary(workspacePath: string): Promise<Map<string,
|
|
|
215
270
|
*/
|
|
216
271
|
export declare function loadVoice(workspacePath: string): Promise<VoiceConfig>;
|
|
217
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Narrative chunk event - captures raw conversational input
|
|
275
|
+
*/
|
|
276
|
+
export declare interface NarrativeChunkEvent extends TimelineEvent {
|
|
277
|
+
type: "narrative_chunk";
|
|
278
|
+
data: {
|
|
279
|
+
/** Raw user input */
|
|
280
|
+
content: string;
|
|
281
|
+
/** Source of input */
|
|
282
|
+
source?: "typing" | "voice" | "paste" | "import";
|
|
283
|
+
/** Context about what prompted this */
|
|
284
|
+
context?: string;
|
|
285
|
+
/** Who is speaking */
|
|
286
|
+
speaker?: "user" | "assistant" | "system";
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
218
290
|
/**
|
|
219
291
|
* Parse style rules markdown
|
|
220
292
|
*/
|
|
@@ -317,11 +389,42 @@ export declare interface StyleViolation {
|
|
|
317
389
|
severity: "error" | "warning" | "info";
|
|
318
390
|
}
|
|
319
391
|
|
|
392
|
+
/**
|
|
393
|
+
* Base timeline event structure
|
|
394
|
+
*/
|
|
395
|
+
export declare interface TimelineEvent {
|
|
396
|
+
/** ISO 8601 timestamp */
|
|
397
|
+
timestamp: string;
|
|
398
|
+
/** Event type identifier */
|
|
399
|
+
type: TimelineEventType;
|
|
400
|
+
/** Event-specific data */
|
|
401
|
+
data: Record<string, any>;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Timeline event types for document lifecycle
|
|
406
|
+
*/
|
|
407
|
+
export declare type TimelineEventType = "document_created" | "outline_created" | "draft_created" | "revision_added" | "evidence_added" | "exported" | "version_incremented" | "version_published" | "narrative_chunk" | "checkpoint_created" | "checkpoint_restored";
|
|
408
|
+
|
|
320
409
|
/**
|
|
321
410
|
* Validate document content against style rules
|
|
322
411
|
*/
|
|
323
412
|
export declare function validateStyle(content: string, rules: StyleRules): StyleValidationResult;
|
|
324
413
|
|
|
414
|
+
/**
|
|
415
|
+
* Version history entry
|
|
416
|
+
*/
|
|
417
|
+
export declare interface VersionHistoryEntry {
|
|
418
|
+
/** Version number (e.g., "0.1", "1.0") */
|
|
419
|
+
version: string;
|
|
420
|
+
/** When this version was created */
|
|
421
|
+
timestamp: string;
|
|
422
|
+
/** Draft file path for this version */
|
|
423
|
+
draftPath?: string;
|
|
424
|
+
/** Notes about this version */
|
|
425
|
+
notes?: string;
|
|
426
|
+
}
|
|
427
|
+
|
|
325
428
|
/**
|
|
326
429
|
* Voice and tone configuration
|
|
327
430
|
*/
|
|
@@ -340,22 +443,14 @@ export declare interface VoiceConfig {
|
|
|
340
443
|
|
|
341
444
|
export declare const VoiceConfigSchema: z.ZodObject<{
|
|
342
445
|
tone: z.ZodString;
|
|
343
|
-
pointOfView: z.ZodEnum<
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
examplePhrases?: string[] | undefined;
|
|
353
|
-
}, {
|
|
354
|
-
tone: string;
|
|
355
|
-
pointOfView: "first" | "second" | "third";
|
|
356
|
-
styleNotes: string[];
|
|
357
|
-
avoid: string[];
|
|
358
|
-
examplePhrases?: string[] | undefined;
|
|
359
|
-
}>;
|
|
446
|
+
pointOfView: z.ZodEnum<{
|
|
447
|
+
first: "first";
|
|
448
|
+
second: "second";
|
|
449
|
+
third: "third";
|
|
450
|
+
}>;
|
|
451
|
+
styleNotes: z.ZodArray<z.ZodString>;
|
|
452
|
+
avoid: z.ZodArray<z.ZodString>;
|
|
453
|
+
examplePhrases: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
454
|
+
}, z.core.$strip>;
|
|
360
455
|
|
|
361
456
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { D, a, R, c, h, l, b, p, d } from "./loader-
|
|
2
|
+
import { D, a, R, c, h, l, b, p, d } from "./loader-DJHV70rz.js";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
const DocumentConfigSchema = z.object({
|
|
5
5
|
id: z.string(),
|
|
@@ -10,7 +10,7 @@ const DocumentConfigSchema = z.object({
|
|
|
10
10
|
updatedAt: z.coerce.date(),
|
|
11
11
|
targetWordCount: z.number().optional(),
|
|
12
12
|
audience: z.string().optional(),
|
|
13
|
-
metadata: z.record(z.unknown()).optional()
|
|
13
|
+
metadata: z.record(z.string(), z.unknown()).optional()
|
|
14
14
|
});
|
|
15
15
|
const VoiceConfigSchema = z.object({
|
|
16
16
|
tone: z.string(),
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/schema.ts","../src/voice/prompt-builder.ts","../src/style/validator.ts","../src/style/reporter.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const DocumentConfigSchema = z.object({\n id: z.string(),\n title: z.string(),\n type: z.enum([\"blog-post\", \"podcast-script\", \"technical-doc\", \"newsletter\", \"custom\"]),\n status: z.enum([\"idea\", \"outlined\", \"drafting\", \"revising\", \"final\", \"exported\"]),\n createdAt: z.coerce.date(),\n updatedAt: z.coerce.date(),\n targetWordCount: z.number().optional(),\n audience: z.string().optional(),\n metadata: z.record(z.unknown()).optional(),\n});\n\nexport const VoiceConfigSchema = z.object({\n tone: z.string(),\n pointOfView: z.enum([\"first\", \"second\", \"third\"]),\n styleNotes: z.array(z.string()),\n avoid: z.array(z.string()),\n examplePhrases: z.array(z.string()).optional(),\n});\n\nexport const DocumentObjectivesSchema = z.object({\n primaryGoal: z.string(),\n secondaryGoals: z.array(z.string()),\n callToAction: z.string().optional(),\n keyTakeaways: z.array(z.string()),\n emotionalArc: z.string().optional(),\n});\n","import type { VoiceConfig } from \"../types.js\";\n\n/**\n * Build a prompt section describing the voice/tone\n */\nexport function buildVoicePrompt(voice: VoiceConfig): string {\n const sections: string[] = [];\n \n sections.push(`## Writing Voice\\n`);\n sections.push(`Tone: ${voice.tone}`);\n sections.push(`Point of view: ${formatPointOfView(voice.pointOfView)}`);\n \n if (voice.styleNotes.length > 0) {\n sections.push(`\\n### Style Guidelines\\n`);\n sections.push(`Do:\\n${voice.styleNotes.map(n => `- ${n}`).join(\"\\n\")}`);\n }\n \n if (voice.avoid.length > 0) {\n sections.push(`\\nAvoid:\\n${voice.avoid.map(a => `- ${a}`).join(\"\\n\")}`);\n }\n \n if (voice.examplePhrases && voice.examplePhrases.length > 0) {\n sections.push(`\\n### Example Phrases\\n`);\n sections.push(voice.examplePhrases.map(p => `\"${p}\"`).join(\"\\n\"));\n }\n \n return sections.join(\"\\n\");\n}\n\nfunction formatPointOfView(pov: \"first\" | \"second\" | \"third\"): string {\n switch (pov) {\n case \"first\": return \"First person (I, we)\";\n case \"second\": return \"Second person (you)\";\n case \"third\": return \"Third person (they, it)\";\n }\n}\n","export interface StyleViolation {\n rule: string;\n message: string;\n line?: number;\n severity: \"error\" | \"warning\" | \"info\";\n}\n\nexport interface StyleValidationResult {\n valid: boolean;\n violations: StyleViolation[];\n stats: DocumentStats;\n}\n\nexport interface DocumentStats {\n wordCount: number;\n sentenceCount: number;\n paragraphCount: number;\n avgWordsPerSentence: number;\n avgSentencesPerParagraph: number;\n}\n\n/**\n * Validate document content against style rules\n */\nexport function validateStyle(\n content: string,\n rules: StyleRules\n): StyleValidationResult {\n const violations: StyleViolation[] = [];\n const stats = calculateStats(content);\n \n // Check word count\n if (rules.maxWordCount && stats.wordCount > rules.maxWordCount) {\n violations.push({\n rule: \"max-word-count\",\n message: `Document has ${stats.wordCount} words, exceeds max of ${rules.maxWordCount}`,\n severity: \"warning\",\n });\n }\n \n if (rules.minWordCount && stats.wordCount < rules.minWordCount) {\n violations.push({\n rule: \"min-word-count\",\n message: `Document has ${stats.wordCount} words, below min of ${rules.minWordCount}`,\n severity: \"warning\",\n });\n }\n \n // Check sentence length\n if (rules.maxSentenceLength) {\n const longSentences = findLongSentences(content, rules.maxSentenceLength);\n for (const sentence of longSentences) {\n violations.push({\n rule: \"sentence-length\",\n message: `Sentence has ${sentence.wordCount} words: \"${sentence.preview}...\"`,\n line: sentence.line,\n severity: \"info\",\n });\n }\n }\n \n // Check passive voice\n if (rules.checkPassiveVoice) {\n const passiveInstances = findPassiveVoice(content);\n for (const instance of passiveInstances) {\n violations.push({\n rule: \"passive-voice\",\n message: `Possible passive voice: \"${instance.text}\"`,\n line: instance.line,\n severity: \"info\",\n });\n }\n }\n \n // Check for avoid patterns\n if (rules.avoidPatterns) {\n for (const pattern of rules.avoidPatterns) {\n const regex = new RegExp(pattern, \"gi\");\n const matches = content.matchAll(regex);\n for (const match of matches) {\n violations.push({\n rule: \"avoid-pattern\",\n message: `Found \"${match[0]}\" which should be avoided`,\n severity: \"warning\",\n });\n }\n }\n }\n \n return {\n valid: violations.filter(v => v.severity === \"error\").length === 0,\n violations,\n stats,\n };\n}\n\nexport interface StyleRules {\n maxWordCount?: number;\n minWordCount?: number;\n maxSentenceLength?: number;\n checkPassiveVoice?: boolean;\n avoidPatterns?: string[];\n}\n\n/**\n * Calculate document statistics\n */\nfunction calculateStats(content: string): DocumentStats {\n const words = content.split(/\\s+/).filter(w => w.length > 0);\n const sentences = content.split(/[.!?]+/).filter(s => s.trim().length > 0);\n const paragraphs = content.split(/\\n\\n+/).filter(p => p.trim().length > 0);\n \n return {\n wordCount: words.length,\n sentenceCount: sentences.length,\n paragraphCount: paragraphs.length,\n avgWordsPerSentence: sentences.length > 0 \n ? Math.round(words.length / sentences.length) \n : 0,\n avgSentencesPerParagraph: paragraphs.length > 0 \n ? Math.round(sentences.length / paragraphs.length) \n : 0,\n };\n}\n\n/**\n * Find sentences exceeding word limit\n */\nfunction findLongSentences(\n content: string, \n maxWords: number\n): Array<{ wordCount: number; preview: string; line: number }> {\n const results: Array<{ wordCount: number; preview: string; line: number }> = [];\n const lines = content.split(\"\\n\");\n \n let lineNum = 0;\n for (const line of lines) {\n lineNum++;\n const sentences = line.split(/[.!?]+/);\n for (const sentence of sentences) {\n const words = sentence.trim().split(/\\s+/).filter(w => w.length > 0);\n if (words.length > maxWords) {\n results.push({\n wordCount: words.length,\n preview: sentence.trim().slice(0, 50),\n line: lineNum,\n });\n }\n }\n }\n \n return results;\n}\n\n/**\n * Simple passive voice detection\n */\nfunction findPassiveVoice(content: string): Array<{ text: string; line: number }> {\n const results: Array<{ text: string; line: number }> = [];\n const lines = content.split(\"\\n\");\n \n // Common passive voice patterns\n const passivePatterns = [\n /\\b(was|were|been|being|is|are|am)\\s+\\w+ed\\b/gi,\n /\\b(was|were|been|being|is|are|am)\\s+\\w+en\\b/gi,\n ];\n \n let lineNum = 0;\n for (const line of lines) {\n lineNum++;\n for (const pattern of passivePatterns) {\n const matches = line.matchAll(pattern);\n for (const match of matches) {\n results.push({\n text: match[0],\n line: lineNum,\n });\n }\n }\n }\n \n return results;\n}\n","import chalk from \"chalk\";\nimport type { StyleValidationResult, StyleViolation } from \"./validator.js\";\n\n/**\n * Format style validation result for terminal\n */\nexport function formatStyleReport(result: StyleValidationResult): string {\n const lines: string[] = [];\n \n lines.push(chalk.cyan(\"\\n📊 Document Statistics\"));\n lines.push(chalk.gray(` Words: ${result.stats.wordCount}`));\n lines.push(chalk.gray(` Sentences: ${result.stats.sentenceCount}`));\n lines.push(chalk.gray(` Paragraphs: ${result.stats.paragraphCount}`));\n lines.push(chalk.gray(` Avg words/sentence: ${result.stats.avgWordsPerSentence}`));\n \n if (result.violations.length === 0) {\n lines.push(chalk.green(\"\\n✅ No style violations found.\"));\n return lines.join(\"\\n\");\n }\n \n lines.push(chalk.yellow(`\\n⚠️ Style Issues (${result.violations.length}):`));\n \n const grouped = groupViolations(result.violations);\n \n for (const [severity, violations] of Object.entries(grouped)) {\n if (violations.length === 0) continue;\n \n const icon = severity === \"error\" ? \"❌\" : severity === \"warning\" ? \"⚠️\" : \"ℹ️\";\n const color = severity === \"error\" ? chalk.red : severity === \"warning\" ? chalk.yellow : chalk.gray;\n \n lines.push(color(`\\n${icon} ${severity.toUpperCase()} (${violations.length}):`));\n for (const v of violations.slice(0, 5)) {\n const lineInfo = v.line ? ` (line ${v.line})` : \"\";\n lines.push(color(` - ${v.message}${lineInfo}`));\n }\n if (violations.length > 5) {\n lines.push(color(` ... and ${violations.length - 5} more`));\n }\n }\n \n return lines.join(\"\\n\");\n}\n\nfunction groupViolations(violations: StyleViolation[]): Record<string, StyleViolation[]> {\n return {\n error: violations.filter(v => v.severity === \"error\"),\n warning: violations.filter(v => v.severity === \"warning\"),\n info: violations.filter(v => v.severity === \"info\"),\n };\n}\n"],"names":["a","p"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/schema.ts","../src/voice/prompt-builder.ts","../src/style/validator.ts","../src/style/reporter.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const DocumentConfigSchema = z.object({\n id: z.string(),\n title: z.string(),\n type: z.enum([\"blog-post\", \"podcast-script\", \"technical-doc\", \"newsletter\", \"custom\"]),\n status: z.enum([\"idea\", \"outlined\", \"drafting\", \"revising\", \"final\", \"exported\"]),\n createdAt: z.coerce.date(),\n updatedAt: z.coerce.date(),\n targetWordCount: z.number().optional(),\n audience: z.string().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport const VoiceConfigSchema = z.object({\n tone: z.string(),\n pointOfView: z.enum([\"first\", \"second\", \"third\"]),\n styleNotes: z.array(z.string()),\n avoid: z.array(z.string()),\n examplePhrases: z.array(z.string()).optional(),\n});\n\nexport const DocumentObjectivesSchema = z.object({\n primaryGoal: z.string(),\n secondaryGoals: z.array(z.string()),\n callToAction: z.string().optional(),\n keyTakeaways: z.array(z.string()),\n emotionalArc: z.string().optional(),\n});\n","import type { VoiceConfig } from \"../types.js\";\n\n/**\n * Build a prompt section describing the voice/tone\n */\nexport function buildVoicePrompt(voice: VoiceConfig): string {\n const sections: string[] = [];\n \n sections.push(`## Writing Voice\\n`);\n sections.push(`Tone: ${voice.tone}`);\n sections.push(`Point of view: ${formatPointOfView(voice.pointOfView)}`);\n \n if (voice.styleNotes.length > 0) {\n sections.push(`\\n### Style Guidelines\\n`);\n sections.push(`Do:\\n${voice.styleNotes.map(n => `- ${n}`).join(\"\\n\")}`);\n }\n \n if (voice.avoid.length > 0) {\n sections.push(`\\nAvoid:\\n${voice.avoid.map(a => `- ${a}`).join(\"\\n\")}`);\n }\n \n if (voice.examplePhrases && voice.examplePhrases.length > 0) {\n sections.push(`\\n### Example Phrases\\n`);\n sections.push(voice.examplePhrases.map(p => `\"${p}\"`).join(\"\\n\"));\n }\n \n return sections.join(\"\\n\");\n}\n\nfunction formatPointOfView(pov: \"first\" | \"second\" | \"third\"): string {\n switch (pov) {\n case \"first\": return \"First person (I, we)\";\n case \"second\": return \"Second person (you)\";\n case \"third\": return \"Third person (they, it)\";\n }\n}\n","export interface StyleViolation {\n rule: string;\n message: string;\n line?: number;\n severity: \"error\" | \"warning\" | \"info\";\n}\n\nexport interface StyleValidationResult {\n valid: boolean;\n violations: StyleViolation[];\n stats: DocumentStats;\n}\n\nexport interface DocumentStats {\n wordCount: number;\n sentenceCount: number;\n paragraphCount: number;\n avgWordsPerSentence: number;\n avgSentencesPerParagraph: number;\n}\n\n/**\n * Validate document content against style rules\n */\nexport function validateStyle(\n content: string,\n rules: StyleRules\n): StyleValidationResult {\n const violations: StyleViolation[] = [];\n const stats = calculateStats(content);\n \n // Check word count\n if (rules.maxWordCount && stats.wordCount > rules.maxWordCount) {\n violations.push({\n rule: \"max-word-count\",\n message: `Document has ${stats.wordCount} words, exceeds max of ${rules.maxWordCount}`,\n severity: \"warning\",\n });\n }\n \n if (rules.minWordCount && stats.wordCount < rules.minWordCount) {\n violations.push({\n rule: \"min-word-count\",\n message: `Document has ${stats.wordCount} words, below min of ${rules.minWordCount}`,\n severity: \"warning\",\n });\n }\n \n // Check sentence length\n if (rules.maxSentenceLength) {\n const longSentences = findLongSentences(content, rules.maxSentenceLength);\n for (const sentence of longSentences) {\n violations.push({\n rule: \"sentence-length\",\n message: `Sentence has ${sentence.wordCount} words: \"${sentence.preview}...\"`,\n line: sentence.line,\n severity: \"info\",\n });\n }\n }\n \n // Check passive voice\n if (rules.checkPassiveVoice) {\n const passiveInstances = findPassiveVoice(content);\n for (const instance of passiveInstances) {\n violations.push({\n rule: \"passive-voice\",\n message: `Possible passive voice: \"${instance.text}\"`,\n line: instance.line,\n severity: \"info\",\n });\n }\n }\n \n // Check for avoid patterns\n if (rules.avoidPatterns) {\n for (const pattern of rules.avoidPatterns) {\n const regex = new RegExp(pattern, \"gi\");\n const matches = content.matchAll(regex);\n for (const match of matches) {\n violations.push({\n rule: \"avoid-pattern\",\n message: `Found \"${match[0]}\" which should be avoided`,\n severity: \"warning\",\n });\n }\n }\n }\n \n return {\n valid: violations.filter(v => v.severity === \"error\").length === 0,\n violations,\n stats,\n };\n}\n\nexport interface StyleRules {\n maxWordCount?: number;\n minWordCount?: number;\n maxSentenceLength?: number;\n checkPassiveVoice?: boolean;\n avoidPatterns?: string[];\n}\n\n/**\n * Calculate document statistics\n */\nfunction calculateStats(content: string): DocumentStats {\n const words = content.split(/\\s+/).filter(w => w.length > 0);\n const sentences = content.split(/[.!?]+/).filter(s => s.trim().length > 0);\n const paragraphs = content.split(/\\n\\n+/).filter(p => p.trim().length > 0);\n \n return {\n wordCount: words.length,\n sentenceCount: sentences.length,\n paragraphCount: paragraphs.length,\n avgWordsPerSentence: sentences.length > 0 \n ? Math.round(words.length / sentences.length) \n : 0,\n avgSentencesPerParagraph: paragraphs.length > 0 \n ? Math.round(sentences.length / paragraphs.length) \n : 0,\n };\n}\n\n/**\n * Find sentences exceeding word limit\n */\nfunction findLongSentences(\n content: string, \n maxWords: number\n): Array<{ wordCount: number; preview: string; line: number }> {\n const results: Array<{ wordCount: number; preview: string; line: number }> = [];\n const lines = content.split(\"\\n\");\n \n let lineNum = 0;\n for (const line of lines) {\n lineNum++;\n const sentences = line.split(/[.!?]+/);\n for (const sentence of sentences) {\n const words = sentence.trim().split(/\\s+/).filter(w => w.length > 0);\n if (words.length > maxWords) {\n results.push({\n wordCount: words.length,\n preview: sentence.trim().slice(0, 50),\n line: lineNum,\n });\n }\n }\n }\n \n return results;\n}\n\n/**\n * Simple passive voice detection\n */\nfunction findPassiveVoice(content: string): Array<{ text: string; line: number }> {\n const results: Array<{ text: string; line: number }> = [];\n const lines = content.split(\"\\n\");\n \n // Common passive voice patterns\n const passivePatterns = [\n /\\b(was|were|been|being|is|are|am)\\s+\\w+ed\\b/gi,\n /\\b(was|were|been|being|is|are|am)\\s+\\w+en\\b/gi,\n ];\n \n let lineNum = 0;\n for (const line of lines) {\n lineNum++;\n for (const pattern of passivePatterns) {\n const matches = line.matchAll(pattern);\n for (const match of matches) {\n results.push({\n text: match[0],\n line: lineNum,\n });\n }\n }\n }\n \n return results;\n}\n","import chalk from \"chalk\";\nimport type { StyleValidationResult, StyleViolation } from \"./validator.js\";\n\n/**\n * Format style validation result for terminal\n */\nexport function formatStyleReport(result: StyleValidationResult): string {\n const lines: string[] = [];\n \n lines.push(chalk.cyan(\"\\n📊 Document Statistics\"));\n lines.push(chalk.gray(` Words: ${result.stats.wordCount}`));\n lines.push(chalk.gray(` Sentences: ${result.stats.sentenceCount}`));\n lines.push(chalk.gray(` Paragraphs: ${result.stats.paragraphCount}`));\n lines.push(chalk.gray(` Avg words/sentence: ${result.stats.avgWordsPerSentence}`));\n \n if (result.violations.length === 0) {\n lines.push(chalk.green(\"\\n✅ No style violations found.\"));\n return lines.join(\"\\n\");\n }\n \n lines.push(chalk.yellow(`\\n⚠️ Style Issues (${result.violations.length}):`));\n \n const grouped = groupViolations(result.violations);\n \n for (const [severity, violations] of Object.entries(grouped)) {\n if (violations.length === 0) continue;\n \n const icon = severity === \"error\" ? \"❌\" : severity === \"warning\" ? \"⚠️\" : \"ℹ️\";\n const color = severity === \"error\" ? chalk.red : severity === \"warning\" ? chalk.yellow : chalk.gray;\n \n lines.push(color(`\\n${icon} ${severity.toUpperCase()} (${violations.length}):`));\n for (const v of violations.slice(0, 5)) {\n const lineInfo = v.line ? ` (line ${v.line})` : \"\";\n lines.push(color(` - ${v.message}${lineInfo}`));\n }\n if (violations.length > 5) {\n lines.push(color(` ... and ${violations.length - 5} more`));\n }\n }\n \n return lines.join(\"\\n\");\n}\n\nfunction groupViolations(violations: StyleViolation[]): Record<string, StyleViolation[]> {\n return {\n error: violations.filter(v => v.severity === \"error\"),\n warning: violations.filter(v => v.severity === \"warning\"),\n info: violations.filter(v => v.severity === \"info\"),\n };\n}\n"],"names":["a","p"],"mappings":"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"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { R as RIOTDOC_STRUCTURE } from "./loader-DJHV70rz.js";
|
|
4
|
+
import { parse } from "yaml";
|
|
5
|
+
async function loadOutline(workspacePath) {
|
|
6
|
+
const outlinePath = join(workspacePath, RIOTDOC_STRUCTURE.outlineFile);
|
|
7
|
+
return await readFile(outlinePath, "utf-8");
|
|
8
|
+
}
|
|
9
|
+
function buildOutlinePrompt(objectives, voice, documentType) {
|
|
10
|
+
return `Generate an outline for a ${documentType}.
|
|
11
|
+
|
|
12
|
+
## Objectives
|
|
13
|
+
|
|
14
|
+
Primary Goal: ${objectives.primaryGoal}
|
|
15
|
+
|
|
16
|
+
Secondary Goals:
|
|
17
|
+
${objectives.secondaryGoals.map((g) => `- ${g}`).join("\n")}
|
|
18
|
+
|
|
19
|
+
Key Takeaways:
|
|
20
|
+
${objectives.keyTakeaways.map((t) => `- ${t}`).join("\n")}
|
|
21
|
+
|
|
22
|
+
${objectives.emotionalArc ? `Emotional Arc: ${objectives.emotionalArc}` : ""}
|
|
23
|
+
|
|
24
|
+
## Voice & Tone
|
|
25
|
+
|
|
26
|
+
Tone: ${voice.tone}
|
|
27
|
+
Point of View: ${voice.pointOfView}
|
|
28
|
+
|
|
29
|
+
## Output Format
|
|
30
|
+
|
|
31
|
+
Create a markdown outline with:
|
|
32
|
+
1. A compelling hook/introduction
|
|
33
|
+
2. 3-5 main sections with bullet points
|
|
34
|
+
3. A conclusion with call to action
|
|
35
|
+
|
|
36
|
+
Use ## for main sections, ### for subsections, and - for bullet points.
|
|
37
|
+
`;
|
|
38
|
+
}
|
|
39
|
+
async function loadDocument(workspacePath) {
|
|
40
|
+
try {
|
|
41
|
+
const configPath = join(workspacePath, RIOTDOC_STRUCTURE.configFile);
|
|
42
|
+
const content = await readFile(configPath, "utf-8");
|
|
43
|
+
const config = parse(content);
|
|
44
|
+
config.createdAt = new Date(config.createdAt);
|
|
45
|
+
config.updatedAt = new Date(config.updatedAt);
|
|
46
|
+
return {
|
|
47
|
+
config,
|
|
48
|
+
voice: { tone: "", pointOfView: "first", styleNotes: [], avoid: [] },
|
|
49
|
+
objectives: { primaryGoal: "", secondaryGoals: [], keyTakeaways: [] },
|
|
50
|
+
evidence: [],
|
|
51
|
+
drafts: [],
|
|
52
|
+
revisions: [],
|
|
53
|
+
workspacePath
|
|
54
|
+
};
|
|
55
|
+
} catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function loadObjectives(workspacePath) {
|
|
60
|
+
const objectivesPath = join(workspacePath, RIOTDOC_STRUCTURE.objectivesFile);
|
|
61
|
+
try {
|
|
62
|
+
const content = await readFile(objectivesPath, "utf-8");
|
|
63
|
+
return parseObjectivesMarkdown(content);
|
|
64
|
+
} catch {
|
|
65
|
+
return {
|
|
66
|
+
primaryGoal: "",
|
|
67
|
+
secondaryGoals: [],
|
|
68
|
+
keyTakeaways: []
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function parseObjectivesMarkdown(content) {
|
|
73
|
+
const objectives = {
|
|
74
|
+
primaryGoal: "",
|
|
75
|
+
secondaryGoals: [],
|
|
76
|
+
keyTakeaways: []
|
|
77
|
+
};
|
|
78
|
+
const goalMatch = content.match(/##\s*Primary\s+Goal\s*\n+([^\n#]+)/i);
|
|
79
|
+
if (goalMatch) {
|
|
80
|
+
objectives.primaryGoal = goalMatch[1].trim().replace(/^_|_$/g, "");
|
|
81
|
+
}
|
|
82
|
+
const lines = content.split("\n");
|
|
83
|
+
const secondaryLines = [];
|
|
84
|
+
let inSecondary = false;
|
|
85
|
+
for (const line of lines) {
|
|
86
|
+
if (/^##\s*Secondary\s+Goals$/i.test(line)) {
|
|
87
|
+
inSecondary = true;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (inSecondary && /^##/.test(line)) {
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
if (inSecondary) {
|
|
94
|
+
secondaryLines.push(line);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (secondaryLines.length > 0) {
|
|
98
|
+
const sectionContent = secondaryLines.join("\n");
|
|
99
|
+
const goals = sectionContent.matchAll(/^[-*]\s+(.+)$/gm);
|
|
100
|
+
for (const goal of goals) {
|
|
101
|
+
const text = goal[1].trim().replace(/^_|_$/g, "");
|
|
102
|
+
if (text && !text.startsWith("Add")) {
|
|
103
|
+
objectives.secondaryGoals.push(text);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const takeawayLines = [];
|
|
108
|
+
let inTakeaways = false;
|
|
109
|
+
for (const line of lines) {
|
|
110
|
+
if (/^##\s*Key\s+Takeaways$/i.test(line)) {
|
|
111
|
+
inTakeaways = true;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (inTakeaways && /^##/.test(line)) {
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
if (inTakeaways) {
|
|
118
|
+
takeawayLines.push(line);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (takeawayLines.length > 0) {
|
|
122
|
+
const sectionContent = takeawayLines.join("\n");
|
|
123
|
+
const takeaways = sectionContent.matchAll(/^\d+\.\s+(.+)$/gm);
|
|
124
|
+
for (const takeaway of takeaways) {
|
|
125
|
+
const text = takeaway[1].trim().replace(/^_|_$/g, "");
|
|
126
|
+
if (text && !text.startsWith("Define")) {
|
|
127
|
+
objectives.keyTakeaways.push(text);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const ctaMatch = content.match(/##\s*Call\s+to\s+Action\s*\n+([^\n#]+)/i);
|
|
132
|
+
if (ctaMatch) {
|
|
133
|
+
const cta = ctaMatch[1].trim().replace(/^_|_$/g, "");
|
|
134
|
+
if (cta && !cta.startsWith("What")) {
|
|
135
|
+
objectives.callToAction = cta;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const arcMatch = content.match(/##\s*Emotional\s+Arc\s*\n+([^\n#]+)/i);
|
|
139
|
+
if (arcMatch) {
|
|
140
|
+
const arc = arcMatch[1].trim().replace(/^_|_$/g, "");
|
|
141
|
+
if (arc && !arc.startsWith("Describe")) {
|
|
142
|
+
objectives.emotionalArc = arc;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return objectives;
|
|
146
|
+
}
|
|
147
|
+
export {
|
|
148
|
+
loadObjectives as a,
|
|
149
|
+
buildOutlinePrompt as b,
|
|
150
|
+
loadOutline as c,
|
|
151
|
+
loadDocument as l
|
|
152
|
+
};
|
|
153
|
+
//# sourceMappingURL=loader-Cvfo7vBn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader-Cvfo7vBn.js","sources":["../src/outline/generator.ts","../src/workspace/loader.ts","../src/objectives/loader.ts"],"sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { RIOTDOC_STRUCTURE } from \"../constants.js\";\nimport type { DocumentObjectives, VoiceConfig } from \"../types.js\";\n\nexport interface OutlineSection {\n title: string;\n points: string[];\n subsections?: OutlineSection[];\n}\n\nexport interface Outline {\n title: string;\n hook: string;\n sections: OutlineSection[];\n conclusion: string;\n}\n\n/**\n * Load outline from workspace\n */\nexport async function loadOutline(workspacePath: string): Promise<string> {\n const outlinePath = join(workspacePath, RIOTDOC_STRUCTURE.outlineFile);\n return await readFile(outlinePath, \"utf-8\");\n}\n\n/**\n * Save outline to workspace\n */\nexport async function saveOutline(workspacePath: string, content: string): Promise<void> {\n const outlinePath = join(workspacePath, RIOTDOC_STRUCTURE.outlineFile);\n await writeFile(outlinePath, content, \"utf-8\");\n}\n\n/**\n * Build prompt for outline generation\n */\nexport function buildOutlinePrompt(\n objectives: DocumentObjectives,\n voice: VoiceConfig,\n documentType: string\n): string {\n return `Generate an outline for a ${documentType}.\n\n## Objectives\n\nPrimary Goal: ${objectives.primaryGoal}\n\nSecondary Goals:\n${objectives.secondaryGoals.map(g => `- ${g}`).join(\"\\n\")}\n\nKey Takeaways:\n${objectives.keyTakeaways.map(t => `- ${t}`).join(\"\\n\")}\n\n${objectives.emotionalArc ? `Emotional Arc: ${objectives.emotionalArc}` : \"\"}\n\n## Voice & Tone\n\nTone: ${voice.tone}\nPoint of View: ${voice.pointOfView}\n\n## Output Format\n\nCreate a markdown outline with:\n1. A compelling hook/introduction\n2. 3-5 main sections with bullet points\n3. A conclusion with call to action\n\nUse ## for main sections, ### for subsections, and - for bullet points.\n`;\n}\n\n/**\n * Parse outline markdown into structure\n */\nexport function parseOutline(content: string): Outline {\n const lines = content.split(\"\\n\");\n const outline: Outline = {\n title: \"\",\n hook: \"\",\n sections: [],\n conclusion: \"\",\n };\n \n let currentSection: OutlineSection | null = null;\n let inIntro = false;\n let inConclusion = false;\n \n for (const line of lines) {\n // Title\n if (line.startsWith(\"# \")) {\n outline.title = line.slice(2).trim();\n continue;\n }\n \n // Main section\n if (line.startsWith(\"## \")) {\n const title = line.slice(3).trim().toLowerCase();\n if (title.includes(\"intro\") || title.includes(\"hook\")) {\n inIntro = true;\n inConclusion = false;\n currentSection = null;\n } else if (title.includes(\"conclusion\")) {\n inIntro = false;\n inConclusion = true;\n currentSection = null;\n } else {\n inIntro = false;\n inConclusion = false;\n currentSection = { title: line.slice(3).trim(), points: [] };\n outline.sections.push(currentSection);\n }\n continue;\n }\n \n // Bullet point\n if (line.match(/^[-*]\\s+/)) {\n const point = line.replace(/^[-*]\\s+/, \"\").trim();\n if (inIntro) {\n outline.hook += (outline.hook ? \"\\n\" : \"\") + point;\n } else if (inConclusion) {\n outline.conclusion += (outline.conclusion ? \"\\n\" : \"\") + point;\n } else if (currentSection) {\n currentSection.points.push(point);\n }\n }\n }\n \n return outline;\n}\n\n/**\n * Format outline structure as markdown\n */\nexport function formatOutline(outline: Outline): string {\n const parts: string[] = [];\n \n parts.push(`# ${outline.title}\\n`);\n \n if (outline.hook) {\n parts.push(`## Introduction\\n`);\n parts.push(outline.hook.split(\"\\n\").map(p => `- ${p}`).join(\"\\n\"));\n parts.push(\"\");\n }\n \n for (const section of outline.sections) {\n parts.push(`## ${section.title}\\n`);\n parts.push(section.points.map(p => `- ${p}`).join(\"\\n\"));\n parts.push(\"\");\n }\n \n if (outline.conclusion) {\n parts.push(`## Conclusion\\n`);\n parts.push(outline.conclusion.split(\"\\n\").map(p => `- ${p}`).join(\"\\n\"));\n }\n \n return parts.join(\"\\n\");\n}\n","import { readFile, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { parse } from \"yaml\";\nimport { RIOTDOC_STRUCTURE } from \"../constants.js\";\nimport type { RiotDoc, DocumentConfig } from \"../types.js\";\n\n/**\n * Load document from workspace\n */\nexport async function loadDocument(workspacePath: string): Promise<RiotDoc | null> {\n try {\n const configPath = join(workspacePath, RIOTDOC_STRUCTURE.configFile);\n const content = await readFile(configPath, \"utf-8\");\n const config = parse(content) as DocumentConfig;\n \n // Convert date strings to Date objects\n config.createdAt = new Date(config.createdAt);\n config.updatedAt = new Date(config.updatedAt);\n \n return {\n config,\n voice: { tone: \"\", pointOfView: \"first\", styleNotes: [], avoid: [] },\n objectives: { primaryGoal: \"\", secondaryGoals: [], keyTakeaways: [] },\n evidence: [],\n drafts: [],\n revisions: [],\n workspacePath,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Check if path is a RiotDoc workspace\n */\nexport async function isRiotDocWorkspace(path: string): Promise<boolean> {\n try {\n const configPath = join(path, RIOTDOC_STRUCTURE.configFile);\n await stat(configPath);\n return true;\n } catch {\n return false;\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { RIOTDOC_STRUCTURE } from \"../constants.js\";\nimport type { DocumentObjectives } from \"../types.js\";\n\n/**\n * Load objectives from workspace\n */\nexport async function loadObjectives(workspacePath: string): Promise<DocumentObjectives> {\n const objectivesPath = join(workspacePath, RIOTDOC_STRUCTURE.objectivesFile);\n \n try {\n const content = await readFile(objectivesPath, \"utf-8\");\n return parseObjectivesMarkdown(content);\n } catch {\n return {\n primaryGoal: \"\",\n secondaryGoals: [],\n keyTakeaways: [],\n };\n }\n}\n\n/**\n * Parse objectives markdown\n */\nfunction parseObjectivesMarkdown(content: string): DocumentObjectives {\n const objectives: DocumentObjectives = {\n primaryGoal: \"\",\n secondaryGoals: [],\n keyTakeaways: [],\n };\n \n // Extract primary goal\n const goalMatch = content.match(/##\\s*Primary\\s+Goal\\s*\\n+([^\\n#]+)/i);\n if (goalMatch) {\n objectives.primaryGoal = goalMatch[1].trim().replace(/^_|_$/g, \"\");\n }\n \n // Extract secondary goals\n // Use line-by-line parsing to avoid polynomial regex\n const lines = content.split('\\n');\n const secondaryLines: string[] = [];\n let inSecondary = false;\n \n for (const line of lines) {\n if (/^##\\s*Secondary\\s+Goals$/i.test(line)) {\n inSecondary = true;\n continue;\n }\n if (inSecondary && /^##/.test(line)) {\n break;\n }\n if (inSecondary) {\n secondaryLines.push(line);\n }\n }\n \n if (secondaryLines.length > 0) {\n const sectionContent = secondaryLines.join('\\n');\n const goals = sectionContent.matchAll(/^[-*]\\s+(.+)$/gm);\n for (const goal of goals) {\n const text = goal[1].trim().replace(/^_|_$/g, \"\");\n if (text && !text.startsWith(\"Add\")) {\n objectives.secondaryGoals.push(text);\n }\n }\n }\n \n // Extract key takeaways\n // Use line-by-line parsing to avoid polynomial regex\n const takeawayLines: string[] = [];\n let inTakeaways = false;\n \n for (const line of lines) {\n if (/^##\\s*Key\\s+Takeaways$/i.test(line)) {\n inTakeaways = true;\n continue;\n }\n if (inTakeaways && /^##/.test(line)) {\n break;\n }\n if (inTakeaways) {\n takeawayLines.push(line);\n }\n }\n \n if (takeawayLines.length > 0) {\n const sectionContent = takeawayLines.join('\\n');\n const takeaways = sectionContent.matchAll(/^\\d+\\.\\s+(.+)$/gm);\n for (const takeaway of takeaways) {\n const text = takeaway[1].trim().replace(/^_|_$/g, \"\");\n if (text && !text.startsWith(\"Define\")) {\n objectives.keyTakeaways.push(text);\n }\n }\n }\n \n // Extract call to action\n const ctaMatch = content.match(/##\\s*Call\\s+to\\s+Action\\s*\\n+([^\\n#]+)/i);\n if (ctaMatch) {\n const cta = ctaMatch[1].trim().replace(/^_|_$/g, \"\");\n if (cta && !cta.startsWith(\"What\")) {\n objectives.callToAction = cta;\n }\n }\n \n // Extract emotional arc\n const arcMatch = content.match(/##\\s*Emotional\\s+Arc\\s*\\n+([^\\n#]+)/i);\n if (arcMatch) {\n const arc = arcMatch[1].trim().replace(/^_|_$/g, \"\");\n if (arc && !arc.startsWith(\"Describe\")) {\n objectives.emotionalArc = arc;\n }\n }\n \n return objectives;\n}\n"],"names":[],"mappings":"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"}
|