@riotprompt/riotdoc 1.0.3-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 -145
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +122 -0
- package/dist/index.js +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 +13 -6
- 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-Jj2cSi3H.js +0 -6387
- package/dist/loader-Jj2cSi3H.js.map +0 -1
|
@@ -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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"}
|
|
@@ -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":"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"}
|
|
@@ -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 { }
|