@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.
@@ -0,0 +1,389 @@
1
+ import { mkdir, writeFile, readFile, stat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { stringify } from "yaml";
4
+ const RIOTDOC_STRUCTURE = {
5
+ /** Main configuration file */
6
+ configFile: "riotdoc.yaml",
7
+ /** Objectives document */
8
+ objectivesFile: "OBJECTIVES.md",
9
+ /** Outline document */
10
+ outlineFile: "OUTLINE.md",
11
+ /** Voice configuration directory */
12
+ voiceDir: "voice",
13
+ /** Voice files */
14
+ voiceFiles: {
15
+ tone: "tone.md",
16
+ styleRules: "style-rules.md",
17
+ glossary: "glossary.md"
18
+ },
19
+ /** Evidence directory */
20
+ evidenceDir: "evidence",
21
+ /** Drafts directory */
22
+ draftsDir: "drafts",
23
+ /** Revisions directory */
24
+ revisionsDir: "revisions",
25
+ /** Export directory */
26
+ exportDir: "export"
27
+ };
28
+ const DEFAULT_VOICE = {
29
+ tone: "conversational",
30
+ pointOfView: "first",
31
+ styleNotes: [
32
+ "Use active voice",
33
+ "Keep sentences concise",
34
+ "Include concrete examples"
35
+ ],
36
+ avoid: [
37
+ "Jargon without explanation",
38
+ "Passive voice",
39
+ "Vague statements"
40
+ ]
41
+ };
42
+ const DEFAULT_OBJECTIVES = {
43
+ primaryGoal: "",
44
+ secondaryGoals: [],
45
+ keyTakeaways: []
46
+ };
47
+ async function createWorkspace(options) {
48
+ const { path: workspacePath, title, type } = options;
49
+ const id = options.id || workspacePath.split("/").pop() || "document";
50
+ await mkdir(workspacePath, { recursive: true });
51
+ await mkdir(join(workspacePath, RIOTDOC_STRUCTURE.voiceDir), { recursive: true });
52
+ await mkdir(join(workspacePath, RIOTDOC_STRUCTURE.evidenceDir), { recursive: true });
53
+ await mkdir(join(workspacePath, RIOTDOC_STRUCTURE.draftsDir), { recursive: true });
54
+ await mkdir(join(workspacePath, RIOTDOC_STRUCTURE.revisionsDir), { recursive: true });
55
+ await mkdir(join(workspacePath, RIOTDOC_STRUCTURE.exportDir), { recursive: true });
56
+ const config = {
57
+ id,
58
+ title,
59
+ type,
60
+ status: "idea",
61
+ createdAt: /* @__PURE__ */ new Date(),
62
+ updatedAt: /* @__PURE__ */ new Date()
63
+ };
64
+ await writeFile(
65
+ join(workspacePath, RIOTDOC_STRUCTURE.configFile),
66
+ stringify(config),
67
+ "utf-8"
68
+ );
69
+ const objectives = { ...DEFAULT_OBJECTIVES, ...options.objectives };
70
+ await writeFile(
71
+ join(workspacePath, RIOTDOC_STRUCTURE.objectivesFile),
72
+ generateObjectivesMarkdown(title, objectives),
73
+ "utf-8"
74
+ );
75
+ await writeFile(
76
+ join(workspacePath, RIOTDOC_STRUCTURE.outlineFile),
77
+ generateOutlineMarkdown(title),
78
+ "utf-8"
79
+ );
80
+ const voice = { ...DEFAULT_VOICE, ...options.voice };
81
+ await writeFile(
82
+ join(workspacePath, RIOTDOC_STRUCTURE.voiceDir, RIOTDOC_STRUCTURE.voiceFiles.tone),
83
+ generateToneMarkdown(voice),
84
+ "utf-8"
85
+ );
86
+ await writeFile(
87
+ join(workspacePath, RIOTDOC_STRUCTURE.voiceDir, RIOTDOC_STRUCTURE.voiceFiles.styleRules),
88
+ generateStyleRulesMarkdown(voice),
89
+ "utf-8"
90
+ );
91
+ await writeFile(
92
+ join(workspacePath, RIOTDOC_STRUCTURE.voiceDir, RIOTDOC_STRUCTURE.voiceFiles.glossary),
93
+ generateGlossaryMarkdown(),
94
+ "utf-8"
95
+ );
96
+ await writeFile(
97
+ join(workspacePath, RIOTDOC_STRUCTURE.evidenceDir, "README.md"),
98
+ generateEvidenceReadme(),
99
+ "utf-8"
100
+ );
101
+ return workspacePath;
102
+ }
103
+ function generateObjectivesMarkdown(title, objectives) {
104
+ return `# ${title} - Objectives
105
+
106
+ ## Primary Goal
107
+
108
+ ${objectives.primaryGoal || "_Define the main purpose of this document..._"}
109
+
110
+ ## Secondary Goals
111
+
112
+ ${objectives.secondaryGoals.length > 0 ? objectives.secondaryGoals.map((g) => `- ${g}`).join("\n") : "- _Add secondary objectives..._"}
113
+
114
+ ## Key Takeaways
115
+
116
+ What should readers remember after reading this?
117
+
118
+ ${objectives.keyTakeaways.length > 0 ? objectives.keyTakeaways.map((t, i) => `${i + 1}. ${t}`).join("\n") : "1. _Define key takeaways..._"}
119
+
120
+ ## Call to Action
121
+
122
+ ${objectives.callToAction || "_What should readers do after reading?_"}
123
+
124
+ ## Emotional Arc
125
+
126
+ ${objectives.emotionalArc || "_Describe the emotional journey: hook → tension → resolution_"}
127
+ `;
128
+ }
129
+ function generateOutlineMarkdown(title) {
130
+ return `# ${title} - Outline
131
+
132
+ ## Structure
133
+
134
+ _Define your document structure here..._
135
+
136
+ ### Introduction
137
+
138
+ - Hook
139
+ - Context
140
+ - Thesis/main point
141
+
142
+ ### Body
143
+
144
+ - Section 1
145
+ - Section 2
146
+ - Section 3
147
+
148
+ ### Conclusion
149
+
150
+ - Summary
151
+ - Call to action
152
+ - Final thought
153
+
154
+ ---
155
+
156
+ ## Notes
157
+
158
+ _Add outline notes here..._
159
+ `;
160
+ }
161
+ function generateToneMarkdown(voice) {
162
+ return `# Voice & Tone
163
+
164
+ ## Overall Tone
165
+
166
+ ${voice.tone}
167
+
168
+ ## Point of View
169
+
170
+ ${voice.pointOfView === "first" ? "First person (I, we)" : voice.pointOfView === "second" ? "Second person (you)" : "Third person (they, it)"}
171
+
172
+ ## Example Phrases
173
+
174
+ ${voice.examplePhrases?.map((p) => `> "${p}"`).join("\n\n") || "_Add example phrases that capture your voice..._"}
175
+
176
+ ## Notes
177
+
178
+ _Additional tone guidance..._
179
+ `;
180
+ }
181
+ function generateStyleRulesMarkdown(voice) {
182
+ return `# Style Rules
183
+
184
+ ## Do
185
+
186
+ ${voice.styleNotes.map((n) => `- ${n}`).join("\n")}
187
+
188
+ ## Don't
189
+
190
+ ${voice.avoid.map((a) => `- ${a}`).join("\n")}
191
+
192
+ ## Formatting
193
+
194
+ - Use headers to break up content
195
+ - Keep paragraphs short (3-4 sentences)
196
+ - Include examples where helpful
197
+
198
+ ## Custom Rules
199
+
200
+ _Add document-specific style rules..._
201
+ `;
202
+ }
203
+ function generateGlossaryMarkdown() {
204
+ return `# Glossary & Spelling
205
+
206
+ ## Terms
207
+
208
+ | Term | Spelling/Usage |
209
+ |------|----------------|
210
+ | _example_ | _Always capitalize_ |
211
+
212
+ ## Abbreviations
213
+
214
+ | Abbreviation | Meaning |
215
+ |--------------|---------|
216
+ | _e.g._ | _for example_ |
217
+
218
+ ## Notes
219
+
220
+ _Add spelling preferences, proper nouns, etc._
221
+ `;
222
+ }
223
+ function generateEvidenceReadme() {
224
+ return `# Evidence & References
225
+
226
+ Place research materials, quotes, data, and other reference materials here.
227
+
228
+ ## Organization
229
+
230
+ - \`research/\` - Research notes and summaries
231
+ - \`quotes/\` - Quotations with attribution
232
+ - \`data/\` - Statistics, charts, data files
233
+ - \`images/\` - Images and diagrams
234
+
235
+ ## Adding Evidence
236
+
237
+ When adding evidence, note:
238
+ - Source/attribution
239
+ - How you plan to use it
240
+ - Any permissions needed
241
+ `;
242
+ }
243
+ async function loadVoice(workspacePath) {
244
+ const voiceDir = join(workspacePath, RIOTDOC_STRUCTURE.voiceDir);
245
+ const tone = await loadToneFile(voiceDir);
246
+ const styleRules = await loadStyleRulesFile(voiceDir);
247
+ return {
248
+ tone: tone.tone,
249
+ pointOfView: tone.pointOfView,
250
+ styleNotes: styleRules.do,
251
+ avoid: styleRules.dont,
252
+ examplePhrases: tone.examplePhrases
253
+ };
254
+ }
255
+ async function loadToneFile(voiceDir) {
256
+ const tonePath = join(voiceDir, RIOTDOC_STRUCTURE.voiceFiles.tone);
257
+ try {
258
+ const content = await readFile(tonePath, "utf-8");
259
+ return parseToneMarkdown(content);
260
+ } catch {
261
+ return {
262
+ tone: "conversational",
263
+ pointOfView: "first"
264
+ };
265
+ }
266
+ }
267
+ function parseToneMarkdown(content) {
268
+ const toneMatch = content.match(/##\s*Overall\s+Tone\s*\n+([^\n#]+)/i);
269
+ const tone = toneMatch ? toneMatch[1].trim() : "conversational";
270
+ let pointOfView = "first";
271
+ if (content.includes("Second person") || content.includes("second person")) {
272
+ pointOfView = "second";
273
+ } else if (content.includes("Third person") || content.includes("third person")) {
274
+ pointOfView = "third";
275
+ }
276
+ const examplePhrases = [];
277
+ const quoteMatches = content.matchAll(/>\s*"([^"]+)"/g);
278
+ for (const match of quoteMatches) {
279
+ examplePhrases.push(match[1]);
280
+ }
281
+ return {
282
+ tone,
283
+ pointOfView,
284
+ examplePhrases: examplePhrases.length > 0 ? examplePhrases : void 0
285
+ };
286
+ }
287
+ async function loadStyleRulesFile(voiceDir) {
288
+ const rulesPath = join(voiceDir, RIOTDOC_STRUCTURE.voiceFiles.styleRules);
289
+ try {
290
+ const content = await readFile(rulesPath, "utf-8");
291
+ return parseStyleRulesMarkdown(content);
292
+ } catch {
293
+ return { do: [], dont: [] };
294
+ }
295
+ }
296
+ function parseStyleRulesMarkdown(content) {
297
+ const doItems = [];
298
+ const dontItems = [];
299
+ const lines = content.split("\n");
300
+ const doLines = [];
301
+ let inDo = false;
302
+ for (const line of lines) {
303
+ if (/^##\s*Do$/i.test(line)) {
304
+ inDo = true;
305
+ continue;
306
+ }
307
+ if (inDo && /^##/.test(line)) {
308
+ break;
309
+ }
310
+ if (inDo) {
311
+ doLines.push(line);
312
+ }
313
+ }
314
+ if (doLines.length > 0) {
315
+ const sectionContent = doLines.join("\n");
316
+ const items = sectionContent.matchAll(/^[-*]\s+(.+)$/gm);
317
+ for (const item of items) {
318
+ doItems.push(item[1].trim());
319
+ }
320
+ }
321
+ const dontLines = [];
322
+ let inDont = false;
323
+ for (const line of lines) {
324
+ if (/^##\s*Don'?t$/i.test(line)) {
325
+ inDont = true;
326
+ continue;
327
+ }
328
+ if (inDont && /^##/.test(line)) {
329
+ break;
330
+ }
331
+ if (inDont) {
332
+ dontLines.push(line);
333
+ }
334
+ }
335
+ if (dontLines.length > 0) {
336
+ const sectionContent = dontLines.join("\n");
337
+ const items = sectionContent.matchAll(/^[-*]\s+(.+)$/gm);
338
+ for (const item of items) {
339
+ dontItems.push(item[1].trim());
340
+ }
341
+ }
342
+ return { do: doItems, dont: dontItems };
343
+ }
344
+ async function loadGlossary(workspacePath) {
345
+ const glossaryPath = join(
346
+ workspacePath,
347
+ RIOTDOC_STRUCTURE.voiceDir,
348
+ RIOTDOC_STRUCTURE.voiceFiles.glossary
349
+ );
350
+ const glossary = /* @__PURE__ */ new Map();
351
+ try {
352
+ const content = await readFile(glossaryPath, "utf-8");
353
+ const tableRows = content.matchAll(/\|\s*([^|]+)\s*\|\s*([^|]+)\s*\|/g);
354
+ for (const row of tableRows) {
355
+ const term = row[1].trim();
356
+ const usage = row[2].trim();
357
+ if (term && usage && !term.startsWith("-") && term !== "Term") {
358
+ glossary.set(term.toLowerCase(), usage);
359
+ }
360
+ }
361
+ } catch {
362
+ }
363
+ return glossary;
364
+ }
365
+ async function hasVoiceConfig(workspacePath) {
366
+ const tonePath = join(
367
+ workspacePath,
368
+ RIOTDOC_STRUCTURE.voiceDir,
369
+ RIOTDOC_STRUCTURE.voiceFiles.tone
370
+ );
371
+ try {
372
+ await stat(tonePath);
373
+ return true;
374
+ } catch {
375
+ return false;
376
+ }
377
+ }
378
+ export {
379
+ DEFAULT_OBJECTIVES as D,
380
+ RIOTDOC_STRUCTURE as R,
381
+ DEFAULT_VOICE as a,
382
+ loadVoice as b,
383
+ createWorkspace as c,
384
+ parseToneMarkdown as d,
385
+ hasVoiceConfig as h,
386
+ loadGlossary as l,
387
+ parseStyleRulesMarkdown as p
388
+ };
389
+ //# sourceMappingURL=loader-DJHV70rz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader-DJHV70rz.js","sources":["../src/constants.ts","../src/workspace/creator.ts","../src/voice/loader.ts"],"sourcesContent":["/**\n * Standard directory structure for a RiotDoc workspace\n */\nexport const RIOTDOC_STRUCTURE = {\n /** Main configuration file */\n configFile: \"riotdoc.yaml\",\n \n /** Objectives document */\n objectivesFile: \"OBJECTIVES.md\",\n \n /** Outline document */\n outlineFile: \"OUTLINE.md\",\n \n /** Voice configuration directory */\n voiceDir: \"voice\",\n \n /** Voice files */\n voiceFiles: {\n tone: \"tone.md\",\n styleRules: \"style-rules.md\",\n glossary: \"glossary.md\",\n },\n \n /** Evidence directory */\n evidenceDir: \"evidence\",\n \n /** Drafts directory */\n draftsDir: \"drafts\",\n \n /** Revisions directory */\n revisionsDir: \"revisions\",\n \n /** Export directory */\n exportDir: \"export\",\n} as const;\n\n/**\n * Default voice configuration\n */\nexport const DEFAULT_VOICE = {\n tone: \"conversational\",\n pointOfView: \"first\" as const,\n styleNotes: [\n \"Use active voice\",\n \"Keep sentences concise\",\n \"Include concrete examples\",\n ],\n avoid: [\n \"Jargon without explanation\",\n \"Passive voice\",\n \"Vague statements\",\n ],\n};\n\n/**\n * Default objectives template\n */\nexport const DEFAULT_OBJECTIVES = {\n primaryGoal: \"\",\n secondaryGoals: [],\n keyTakeaways: [],\n};\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { stringify } from \"yaml\";\nimport { RIOTDOC_STRUCTURE, DEFAULT_VOICE, DEFAULT_OBJECTIVES } from \"../constants.js\";\nimport type { DocumentConfig, VoiceConfig, DocumentObjectives } from \"../types.js\";\n\nexport interface CreateWorkspaceOptions {\n /** Workspace path */\n path: string;\n \n /** Document ID (derived from path if not provided) */\n id?: string;\n \n /** Document title */\n title: string;\n \n /** Document type */\n type: DocumentConfig[\"type\"];\n \n /** Initial voice config (uses defaults if not provided) */\n voice?: Partial<VoiceConfig>;\n \n /** Initial objectives */\n objectives?: Partial<DocumentObjectives>;\n}\n\n/**\n * Create a new RiotDoc workspace\n */\nexport async function createWorkspace(options: CreateWorkspaceOptions): Promise<string> {\n const { path: workspacePath, title, type } = options;\n const id = options.id || workspacePath.split(\"/\").pop() || \"document\";\n \n // Create main directory\n await mkdir(workspacePath, { recursive: true });\n \n // Create subdirectories\n await mkdir(join(workspacePath, RIOTDOC_STRUCTURE.voiceDir), { recursive: true });\n await mkdir(join(workspacePath, RIOTDOC_STRUCTURE.evidenceDir), { recursive: true });\n await mkdir(join(workspacePath, RIOTDOC_STRUCTURE.draftsDir), { recursive: true });\n await mkdir(join(workspacePath, RIOTDOC_STRUCTURE.revisionsDir), { recursive: true });\n await mkdir(join(workspacePath, RIOTDOC_STRUCTURE.exportDir), { recursive: true });\n \n // Create configuration file\n const config: DocumentConfig = {\n id,\n title,\n type,\n status: \"idea\",\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n await writeFile(\n join(workspacePath, RIOTDOC_STRUCTURE.configFile),\n stringify(config),\n \"utf-8\"\n );\n \n // Create objectives file\n const objectives = { ...DEFAULT_OBJECTIVES, ...options.objectives };\n await writeFile(\n join(workspacePath, RIOTDOC_STRUCTURE.objectivesFile),\n generateObjectivesMarkdown(title, objectives),\n \"utf-8\"\n );\n \n // Create outline file (placeholder)\n await writeFile(\n join(workspacePath, RIOTDOC_STRUCTURE.outlineFile),\n generateOutlineMarkdown(title),\n \"utf-8\"\n );\n \n // Create voice files\n const voice = { ...DEFAULT_VOICE, ...options.voice };\n await writeFile(\n join(workspacePath, RIOTDOC_STRUCTURE.voiceDir, RIOTDOC_STRUCTURE.voiceFiles.tone),\n generateToneMarkdown(voice),\n \"utf-8\"\n );\n await writeFile(\n join(workspacePath, RIOTDOC_STRUCTURE.voiceDir, RIOTDOC_STRUCTURE.voiceFiles.styleRules),\n generateStyleRulesMarkdown(voice),\n \"utf-8\"\n );\n await writeFile(\n join(workspacePath, RIOTDOC_STRUCTURE.voiceDir, RIOTDOC_STRUCTURE.voiceFiles.glossary),\n generateGlossaryMarkdown(),\n \"utf-8\"\n );\n \n // Create evidence README\n await writeFile(\n join(workspacePath, RIOTDOC_STRUCTURE.evidenceDir, \"README.md\"),\n generateEvidenceReadme(),\n \"utf-8\"\n );\n \n return workspacePath;\n}\n\nfunction generateObjectivesMarkdown(title: string, objectives: DocumentObjectives): string {\n return `# ${title} - Objectives\n\n## Primary Goal\n\n${objectives.primaryGoal || \"_Define the main purpose of this document..._\"}\n\n## Secondary Goals\n\n${objectives.secondaryGoals.length > 0 \n ? objectives.secondaryGoals.map(g => `- ${g}`).join(\"\\n\")\n : \"- _Add secondary objectives..._\"}\n\n## Key Takeaways\n\nWhat should readers remember after reading this?\n\n${objectives.keyTakeaways.length > 0\n ? objectives.keyTakeaways.map((t, i) => `${i + 1}. ${t}`).join(\"\\n\")\n : \"1. _Define key takeaways..._\"}\n\n## Call to Action\n\n${objectives.callToAction || \"_What should readers do after reading?_\"}\n\n## Emotional Arc\n\n${objectives.emotionalArc || \"_Describe the emotional journey: hook → tension → resolution_\"}\n`;\n}\n\nfunction generateOutlineMarkdown(title: string): string {\n return `# ${title} - Outline\n\n## Structure\n\n_Define your document structure here..._\n\n### Introduction\n\n- Hook\n- Context\n- Thesis/main point\n\n### Body\n\n- Section 1\n- Section 2\n- Section 3\n\n### Conclusion\n\n- Summary\n- Call to action\n- Final thought\n\n---\n\n## Notes\n\n_Add outline notes here..._\n`;\n}\n\nfunction generateToneMarkdown(voice: VoiceConfig): string {\n return `# Voice & Tone\n\n## Overall Tone\n\n${voice.tone}\n\n## Point of View\n\n${voice.pointOfView === \"first\" ? \"First person (I, we)\" : \n voice.pointOfView === \"second\" ? \"Second person (you)\" : \n \"Third person (they, it)\"}\n\n## Example Phrases\n\n${voice.examplePhrases?.map(p => `> \"${p}\"`).join(\"\\n\\n\") || \"_Add example phrases that capture your voice..._\"}\n\n## Notes\n\n_Additional tone guidance..._\n`;\n}\n\nfunction generateStyleRulesMarkdown(voice: VoiceConfig): string {\n return `# Style Rules\n\n## Do\n\n${voice.styleNotes.map(n => `- ${n}`).join(\"\\n\")}\n\n## Don't\n\n${voice.avoid.map(a => `- ${a}`).join(\"\\n\")}\n\n## Formatting\n\n- Use headers to break up content\n- Keep paragraphs short (3-4 sentences)\n- Include examples where helpful\n\n## Custom Rules\n\n_Add document-specific style rules..._\n`;\n}\n\nfunction generateGlossaryMarkdown(): string {\n return `# Glossary & Spelling\n\n## Terms\n\n| Term | Spelling/Usage |\n|------|----------------|\n| _example_ | _Always capitalize_ |\n\n## Abbreviations\n\n| Abbreviation | Meaning |\n|--------------|---------|\n| _e.g._ | _for example_ |\n\n## Notes\n\n_Add spelling preferences, proper nouns, etc._\n`;\n}\n\nfunction generateEvidenceReadme(): string {\n return `# Evidence & References\n\nPlace research materials, quotes, data, and other reference materials here.\n\n## Organization\n\n- \\`research/\\` - Research notes and summaries\n- \\`quotes/\\` - Quotations with attribution\n- \\`data/\\` - Statistics, charts, data files\n- \\`images/\\` - Images and diagrams\n\n## Adding Evidence\n\nWhen adding evidence, note:\n- Source/attribution\n- How you plan to use it\n- Any permissions needed\n`;\n}\n","import { readFile, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { RIOTDOC_STRUCTURE } from \"../constants.js\";\nimport type { VoiceConfig } from \"../types.js\";\n\n/**\n * Load voice configuration from a document workspace\n */\nexport async function loadVoice(workspacePath: string): Promise<VoiceConfig> {\n const voiceDir = join(workspacePath, RIOTDOC_STRUCTURE.voiceDir);\n \n // Load tone.md\n const tone = await loadToneFile(voiceDir);\n \n // Load style-rules.md\n const styleRules = await loadStyleRulesFile(voiceDir);\n \n return {\n tone: tone.tone,\n pointOfView: tone.pointOfView,\n styleNotes: styleRules.do,\n avoid: styleRules.dont,\n examplePhrases: tone.examplePhrases,\n };\n}\n\n/**\n * Parse tone.md file\n */\nasync function loadToneFile(voiceDir: string): Promise<{\n tone: string;\n pointOfView: \"first\" | \"second\" | \"third\";\n examplePhrases?: string[];\n}> {\n const tonePath = join(voiceDir, RIOTDOC_STRUCTURE.voiceFiles.tone);\n \n try {\n const content = await readFile(tonePath, \"utf-8\");\n return parseToneMarkdown(content);\n } catch {\n return {\n tone: \"conversational\",\n pointOfView: \"first\",\n };\n }\n}\n\n/**\n * Parse tone markdown content\n */\nexport function parseToneMarkdown(content: string): {\n tone: string;\n pointOfView: \"first\" | \"second\" | \"third\";\n examplePhrases?: string[];\n} {\n // Extract tone from ## Overall Tone section\n const toneMatch = content.match(/##\\s*Overall\\s+Tone\\s*\\n+([^\\n#]+)/i);\n const tone = toneMatch ? toneMatch[1].trim() : \"conversational\";\n \n // Extract point of view\n let pointOfView: \"first\" | \"second\" | \"third\" = \"first\";\n if (content.includes(\"Second person\") || content.includes(\"second person\")) {\n pointOfView = \"second\";\n } else if (content.includes(\"Third person\") || content.includes(\"third person\")) {\n pointOfView = \"third\";\n }\n \n // Extract example phrases (quoted lines starting with >)\n const examplePhrases: string[] = [];\n const quoteMatches = content.matchAll(/>\\s*\"([^\"]+)\"/g);\n for (const match of quoteMatches) {\n examplePhrases.push(match[1]);\n }\n \n return {\n tone,\n pointOfView,\n examplePhrases: examplePhrases.length > 0 ? examplePhrases : undefined,\n };\n}\n\n/**\n * Parse style-rules.md file\n */\nasync function loadStyleRulesFile(voiceDir: string): Promise<{\n do: string[];\n dont: string[];\n}> {\n const rulesPath = join(voiceDir, RIOTDOC_STRUCTURE.voiceFiles.styleRules);\n \n try {\n const content = await readFile(rulesPath, \"utf-8\");\n return parseStyleRulesMarkdown(content);\n } catch {\n return { do: [], dont: [] };\n }\n}\n\n/**\n * Parse style rules markdown\n */\nexport function parseStyleRulesMarkdown(content: string): {\n do: string[];\n dont: string[];\n} {\n const doItems: string[] = [];\n const dontItems: string[] = [];\n \n // Find ## Do section\n // Use line-by-line parsing to avoid polynomial regex\n const lines = content.split('\\n');\n const doLines: string[] = [];\n let inDo = false;\n \n for (const line of lines) {\n if (/^##\\s*Do$/i.test(line)) {\n inDo = true;\n continue;\n }\n if (inDo && /^##/.test(line)) {\n break;\n }\n if (inDo) {\n doLines.push(line);\n }\n }\n \n if (doLines.length > 0) {\n const sectionContent = doLines.join('\\n');\n const items = sectionContent.matchAll(/^[-*]\\s+(.+)$/gm);\n for (const item of items) {\n doItems.push(item[1].trim());\n }\n }\n \n // Find ## Don't section\n // Use line-by-line parsing to avoid polynomial regex\n const dontLines: string[] = [];\n let inDont = false;\n \n for (const line of lines) {\n if (/^##\\s*Don'?t$/i.test(line)) {\n inDont = true;\n continue;\n }\n if (inDont && /^##/.test(line)) {\n break;\n }\n if (inDont) {\n dontLines.push(line);\n }\n }\n \n if (dontLines.length > 0) {\n const sectionContent = dontLines.join('\\n');\n const items = sectionContent.matchAll(/^[-*]\\s+(.+)$/gm);\n for (const item of items) {\n dontItems.push(item[1].trim());\n }\n }\n \n return { do: doItems, dont: dontItems };\n}\n\n/**\n * Load glossary from workspace\n */\nexport async function loadGlossary(workspacePath: string): Promise<Map<string, string>> {\n const glossaryPath = join(\n workspacePath,\n RIOTDOC_STRUCTURE.voiceDir,\n RIOTDOC_STRUCTURE.voiceFiles.glossary\n );\n \n const glossary = new Map<string, string>();\n \n try {\n const content = await readFile(glossaryPath, \"utf-8\");\n \n // Parse table rows: | term | spelling/usage |\n const tableRows = content.matchAll(/\\|\\s*([^|]+)\\s*\\|\\s*([^|]+)\\s*\\|/g);\n for (const row of tableRows) {\n const term = row[1].trim();\n const usage = row[2].trim();\n if (term && usage && !term.startsWith(\"-\") && term !== \"Term\") {\n glossary.set(term.toLowerCase(), usage);\n }\n }\n } catch {\n // No glossary file\n }\n \n return glossary;\n}\n\n/**\n * Check if voice configuration exists\n */\nexport async function hasVoiceConfig(workspacePath: string): Promise<boolean> {\n const tonePath = join(\n workspacePath,\n RIOTDOC_STRUCTURE.voiceDir,\n RIOTDOC_STRUCTURE.voiceFiles.tone\n );\n \n try {\n await stat(tonePath);\n return true;\n } catch {\n return false;\n }\n}\n"],"names":[],"mappings":";;;AAGO,MAAM,oBAAoB;AAAA;AAAA,EAE7B,YAAY;AAAA;AAAA,EAGZ,gBAAgB;AAAA;AAAA,EAGhB,aAAa;AAAA;AAAA,EAGb,UAAU;AAAA;AAAA,EAGV,YAAY;AAAA,IACR,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,EAAA;AAAA;AAAA,EAId,aAAa;AAAA;AAAA,EAGb,WAAW;AAAA;AAAA,EAGX,cAAc;AAAA;AAAA,EAGd,WAAW;AACf;AAKO,MAAM,gBAAgB;AAAA,EACzB,MAAM;AAAA,EACN,aAAa;AAAA,EACb,YAAY;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAEJ,OAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAER;AAKO,MAAM,qBAAqB;AAAA,EAC9B,aAAa;AAAA,EACb,gBAAgB,CAAA;AAAA,EAChB,cAAc,CAAA;AAClB;AChCA,eAAsB,gBAAgB,SAAkD;AACpF,QAAM,EAAE,MAAM,eAAe,OAAO,SAAS;AAC7C,QAAM,KAAK,QAAQ,MAAM,cAAc,MAAM,GAAG,EAAE,SAAS;AAG3D,QAAM,MAAM,eAAe,EAAE,WAAW,MAAM;AAG9C,QAAM,MAAM,KAAK,eAAe,kBAAkB,QAAQ,GAAG,EAAE,WAAW,MAAM;AAChF,QAAM,MAAM,KAAK,eAAe,kBAAkB,WAAW,GAAG,EAAE,WAAW,MAAM;AACnF,QAAM,MAAM,KAAK,eAAe,kBAAkB,SAAS,GAAG,EAAE,WAAW,MAAM;AACjF,QAAM,MAAM,KAAK,eAAe,kBAAkB,YAAY,GAAG,EAAE,WAAW,MAAM;AACpF,QAAM,MAAM,KAAK,eAAe,kBAAkB,SAAS,GAAG,EAAE,WAAW,MAAM;AAGjF,QAAM,SAAyB;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,+BAAe,KAAA;AAAA,IACf,+BAAe,KAAA;AAAA,EAAK;AAExB,QAAM;AAAA,IACF,KAAK,eAAe,kBAAkB,UAAU;AAAA,IAChD,UAAU,MAAM;AAAA,IAChB;AAAA,EAAA;AAIJ,QAAM,aAAa,EAAE,GAAG,oBAAoB,GAAG,QAAQ,WAAA;AACvD,QAAM;AAAA,IACF,KAAK,eAAe,kBAAkB,cAAc;AAAA,IACpD,2BAA2B,OAAO,UAAU;AAAA,IAC5C;AAAA,EAAA;AAIJ,QAAM;AAAA,IACF,KAAK,eAAe,kBAAkB,WAAW;AAAA,IACjD,wBAAwB,KAAK;AAAA,IAC7B;AAAA,EAAA;AAIJ,QAAM,QAAQ,EAAE,GAAG,eAAe,GAAG,QAAQ,MAAA;AAC7C,QAAM;AAAA,IACF,KAAK,eAAe,kBAAkB,UAAU,kBAAkB,WAAW,IAAI;AAAA,IACjF,qBAAqB,KAAK;AAAA,IAC1B;AAAA,EAAA;AAEJ,QAAM;AAAA,IACF,KAAK,eAAe,kBAAkB,UAAU,kBAAkB,WAAW,UAAU;AAAA,IACvF,2BAA2B,KAAK;AAAA,IAChC;AAAA,EAAA;AAEJ,QAAM;AAAA,IACF,KAAK,eAAe,kBAAkB,UAAU,kBAAkB,WAAW,QAAQ;AAAA,IACrF,yBAAA;AAAA,IACA;AAAA,EAAA;AAIJ,QAAM;AAAA,IACF,KAAK,eAAe,kBAAkB,aAAa,WAAW;AAAA,IAC9D,uBAAA;AAAA,IACA;AAAA,EAAA;AAGJ,SAAO;AACX;AAEA,SAAS,2BAA2B,OAAe,YAAwC;AACvF,SAAO,KAAK,KAAK;AAAA;AAAA;AAAA;AAAA,EAInB,WAAW,eAAe,+CAA+C;AAAA;AAAA;AAAA;AAAA,EAIzE,WAAW,eAAe,SAAS,IAC3B,WAAW,eAAe,IAAI,CAAA,MAAK,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,IACtD,iCAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMzC,WAAW,aAAa,SAAS,IACzB,WAAW,aAAa,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,IACjE,8BAA8B;AAAA;AAAA;AAAA;AAAA,EAItC,WAAW,gBAAgB,yCAAyC;AAAA;AAAA;AAAA;AAAA,EAIpE,WAAW,gBAAgB,+DAA+D;AAAA;AAE5F;AAEA,SAAS,wBAAwB,OAAuB;AACpD,SAAO,KAAK,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8BrB;AAEA,SAAS,qBAAqB,OAA4B;AACtD,SAAO;AAAA;AAAA;AAAA;AAAA,EAIT,MAAM,IAAI;AAAA;AAAA;AAAA;AAAA,EAIV,MAAM,gBAAgB,UAAU,yBAC1B,MAAM,gBAAgB,WAAW,wBAC7B,yBAAyB;AAAA;AAAA;AAAA;AAAA,EAInC,MAAM,gBAAgB,IAAI,CAAA,MAAK,MAAM,CAAC,GAAG,EAAE,KAAK,MAAM,KAAK,kDAAkD;AAAA;AAAA;AAAA;AAAA;AAAA;AAM/G;AAEA,SAAS,2BAA2B,OAA4B;AAC5D,SAAO;AAAA;AAAA;AAAA;AAAA,EAIT,MAAM,WAAW,IAAI,CAAA,MAAK,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA,EAI9C,MAAM,MAAM,IAAI,CAAA,MAAK,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAY3C;AAEA,SAAS,2BAAmC;AACxC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBX;AAEA,SAAS,yBAAiC;AACtC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBX;ACnPA,eAAsB,UAAU,eAA6C;AACzE,QAAM,WAAW,KAAK,eAAe,kBAAkB,QAAQ;AAG/D,QAAM,OAAO,MAAM,aAAa,QAAQ;AAGxC,QAAM,aAAa,MAAM,mBAAmB,QAAQ;AAEpD,SAAO;AAAA,IACH,MAAM,KAAK;AAAA,IACX,aAAa,KAAK;AAAA,IAClB,YAAY,WAAW;AAAA,IACvB,OAAO,WAAW;AAAA,IAClB,gBAAgB,KAAK;AAAA,EAAA;AAE7B;AAKA,eAAe,aAAa,UAIzB;AACC,QAAM,WAAW,KAAK,UAAU,kBAAkB,WAAW,IAAI;AAEjE,MAAI;AACA,UAAM,UAAU,MAAM,SAAS,UAAU,OAAO;AAChD,WAAO,kBAAkB,OAAO;AAAA,EACpC,QAAQ;AACJ,WAAO;AAAA,MACH,MAAM;AAAA,MACN,aAAa;AAAA,IAAA;AAAA,EAErB;AACJ;AAKO,SAAS,kBAAkB,SAIhC;AAEE,QAAM,YAAY,QAAQ,MAAM,qCAAqC;AACrE,QAAM,OAAO,YAAY,UAAU,CAAC,EAAE,SAAS;AAG/C,MAAI,cAA4C;AAChD,MAAI,QAAQ,SAAS,eAAe,KAAK,QAAQ,SAAS,eAAe,GAAG;AACxE,kBAAc;AAAA,EAClB,WAAW,QAAQ,SAAS,cAAc,KAAK,QAAQ,SAAS,cAAc,GAAG;AAC7E,kBAAc;AAAA,EAClB;AAGA,QAAM,iBAA2B,CAAA;AACjC,QAAM,eAAe,QAAQ,SAAS,gBAAgB;AACtD,aAAW,SAAS,cAAc;AAC9B,mBAAe,KAAK,MAAM,CAAC,CAAC;AAAA,EAChC;AAEA,SAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA,gBAAgB,eAAe,SAAS,IAAI,iBAAiB;AAAA,EAAA;AAErE;AAKA,eAAe,mBAAmB,UAG/B;AACC,QAAM,YAAY,KAAK,UAAU,kBAAkB,WAAW,UAAU;AAExE,MAAI;AACA,UAAM,UAAU,MAAM,SAAS,WAAW,OAAO;AACjD,WAAO,wBAAwB,OAAO;AAAA,EAC1C,QAAQ;AACJ,WAAO,EAAE,IAAI,IAAI,MAAM,CAAA,EAAC;AAAA,EAC5B;AACJ;AAKO,SAAS,wBAAwB,SAGtC;AACE,QAAM,UAAoB,CAAA;AAC1B,QAAM,YAAsB,CAAA;AAI5B,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,QAAM,UAAoB,CAAA;AAC1B,MAAI,OAAO;AAEX,aAAW,QAAQ,OAAO;AACtB,QAAI,aAAa,KAAK,IAAI,GAAG;AACzB,aAAO;AACP;AAAA,IACJ;AACA,QAAI,QAAQ,MAAM,KAAK,IAAI,GAAG;AAC1B;AAAA,IACJ;AACA,QAAI,MAAM;AACN,cAAQ,KAAK,IAAI;AAAA,IACrB;AAAA,EACJ;AAEA,MAAI,QAAQ,SAAS,GAAG;AACpB,UAAM,iBAAiB,QAAQ,KAAK,IAAI;AACxC,UAAM,QAAQ,eAAe,SAAS,iBAAiB;AACvD,eAAW,QAAQ,OAAO;AACtB,cAAQ,KAAK,KAAK,CAAC,EAAE,MAAM;AAAA,IAC/B;AAAA,EACJ;AAIA,QAAM,YAAsB,CAAA;AAC5B,MAAI,SAAS;AAEb,aAAW,QAAQ,OAAO;AACtB,QAAI,iBAAiB,KAAK,IAAI,GAAG;AAC7B,eAAS;AACT;AAAA,IACJ;AACA,QAAI,UAAU,MAAM,KAAK,IAAI,GAAG;AAC5B;AAAA,IACJ;AACA,QAAI,QAAQ;AACR,gBAAU,KAAK,IAAI;AAAA,IACvB;AAAA,EACJ;AAEA,MAAI,UAAU,SAAS,GAAG;AACtB,UAAM,iBAAiB,UAAU,KAAK,IAAI;AAC1C,UAAM,QAAQ,eAAe,SAAS,iBAAiB;AACvD,eAAW,QAAQ,OAAO;AACtB,gBAAU,KAAK,KAAK,CAAC,EAAE,MAAM;AAAA,IACjC;AAAA,EACJ;AAEA,SAAO,EAAE,IAAI,SAAS,MAAM,UAAA;AAChC;AAKA,eAAsB,aAAa,eAAqD;AACpF,QAAM,eAAe;AAAA,IACjB;AAAA,IACA,kBAAkB;AAAA,IAClB,kBAAkB,WAAW;AAAA,EAAA;AAGjC,QAAM,+BAAe,IAAA;AAErB,MAAI;AACA,UAAM,UAAU,MAAM,SAAS,cAAc,OAAO;AAGpD,UAAM,YAAY,QAAQ,SAAS,mCAAmC;AACtE,eAAW,OAAO,WAAW;AACzB,YAAM,OAAO,IAAI,CAAC,EAAE,KAAA;AACpB,YAAM,QAAQ,IAAI,CAAC,EAAE,KAAA;AACrB,UAAI,QAAQ,SAAS,CAAC,KAAK,WAAW,GAAG,KAAK,SAAS,QAAQ;AAC3D,iBAAS,IAAI,KAAK,YAAA,GAAe,KAAK;AAAA,MAC1C;AAAA,IACJ;AAAA,EACJ,QAAQ;AAAA,EAER;AAEA,SAAO;AACX;AAKA,eAAsB,eAAe,eAAyC;AAC1E,QAAM,WAAW;AAAA,IACb;AAAA,IACA,kBAAkB;AAAA,IAClB,kBAAkB,WAAW;AAAA,EAAA;AAGjC,MAAI;AACA,UAAM,KAAK,QAAQ;AACnB,WAAO;AAAA,EACX,QAAQ;AACJ,WAAO;AAAA,EACX;AACJ;"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * RiotDoc MCP Server
3
+ *
4
+ * Exposes riotdoc commands, resources, and prompts via MCP.
5
+ *
6
+ * This server provides:
7
+ * - Tools: Document creation and management commands
8
+ * - Resources: Document state, configuration, and content
9
+ * - Prompts: Workflow templates for document operations
10
+ *
11
+ * Uses McpServer high-level API for better progress notification support
12
+ */
13
+ /**
14
+ * Recursively remove undefined values from an object to prevent JSON serialization issues
15
+ * Preserves null values as they are valid in JSON
16
+ */
17
+ export declare function removeUndefinedValues(obj: any): any;
18
+
19
+ export { }