@doquflow/cli 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,9 +4,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runInteractive = runInteractive;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
7
8
  const promises_1 = __importDefault(require("node:fs/promises"));
8
9
  const node_path_1 = __importDefault(require("node:path"));
9
10
  const node_readline_1 = __importDefault(require("node:readline"));
11
+ const init_1 = require("./init");
10
12
  async function prompt(question) {
11
13
  const rl = node_readline_1.default.createInterface({
12
14
  input: process.stdin,
@@ -315,6 +317,23 @@ Record of all wiki operations.
315
317
  const planPath = node_path_1.default.join(docuDir, "PLAN.md");
316
318
  await promises_1.default.writeFile(planPath, planTemplate, "utf8");
317
319
  console.log(" ✓ Created PLAN.md (interactive planning guide)");
320
+ // Generate CLAUDE.md so Claude Code picks up DocuFlow automatically
321
+ const claudeMdContent = (0, init_1.buildClaudeMd)(process.cwd());
322
+ const claudeMdPath = node_path_1.default.join(process.cwd(), "CLAUDE.md");
323
+ if (node_fs_1.default.existsSync(claudeMdPath)) {
324
+ const existing = await promises_1.default.readFile(claudeMdPath, "utf8");
325
+ if (existing.includes("DocuFlow")) {
326
+ const withoutDocuflow = existing.replace(/\n?# DocuFlow[\s\S]*/, "").trimEnd();
327
+ await promises_1.default.writeFile(claudeMdPath, withoutDocuflow + "\n\n" + claudeMdContent, "utf8");
328
+ }
329
+ else {
330
+ await promises_1.default.appendFile(claudeMdPath, "\n\n" + claudeMdContent, "utf8");
331
+ }
332
+ }
333
+ else {
334
+ await promises_1.default.writeFile(claudeMdPath, claudeMdContent, "utf8");
335
+ }
336
+ console.log(" ✓ Created CLAUDE.md (Claude Code will read DocuFlow tool instructions automatically)");
318
337
  console.log("\n✅ Wiki successfully initialized!\n");
319
338
  // Print summary and next steps
320
339
  console.log("📋 Next Steps:");
@@ -323,5 +342,5 @@ Record of all wiki operations.
323
342
  console.log(" 3. Add first source: copy to .docuflow/sources/");
324
343
  console.log(" 4. Ask Claude: 'Ingest README.md into my wiki'");
325
344
  console.log(" 5. Ask Claude: 'What should my wiki contain?'");
326
- console.log("\n💡 Tip: Open .claude/instructions.md to understand how Claude uses Docuflow\n");
345
+ console.log("\n💡 Tip: Claude Code will automatically read CLAUDE.md for DocuFlow instructions.\n");
327
346
  }
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.buildClaudeMd = buildClaudeMd;
6
7
  exports.run = run;
7
8
  const node_fs_1 = __importDefault(require("node:fs"));
8
9
  const promises_1 = __importDefault(require("node:fs/promises"));
@@ -57,6 +58,96 @@ async function copyTemplateFile(templateName, destPath) {
57
58
  }
58
59
  }
59
60
  }
61
+ function buildClaudeMd(projectDir) {
62
+ return `# DocuFlow — AI Documentation Assistant
63
+
64
+ DocuFlow is an MCP server that gives you structured access to this codebase and maintains a living wiki.
65
+ It is registered in your Claude Desktop config and available as MCP tools in every session.
66
+
67
+ ## Codebase Scanner Tools
68
+
69
+ - **read_module** — Analyse a single source file. Returns language, classes, functions, dependencies, DB tables, endpoints, config refs, and raw content (first 8 KB).
70
+ - Example: \`read_module({ path: "src/UserService.cs" })\`
71
+ - **list_modules** — Walk a directory and extract facts for every non-binary file. Use this to understand the full project in one call.
72
+ - Example: \`list_modules({ path: "${projectDir}" })\`
73
+ - **write_spec** — Persist a markdown spec to \`.docuflow/specs/<filename>.md\` and update the index.
74
+ - Example: \`write_spec({ project_path: "${projectDir}", filename: "UserService", content: "# UserService\\n..." })\`
75
+ - **read_specs** — Read previously written specs, optionally filtered by name.
76
+ - Example: \`read_specs({ project_path: "${projectDir}" })\`
77
+
78
+ ## Wiki Pipeline Tools
79
+
80
+ - **ingest_source** — Ingest a markdown file from \`.docuflow/sources/\` and generate wiki pages (entities, concepts).
81
+ - **update_index** — Rebuild \`.docuflow/index.md\` from all wiki pages.
82
+ - **list_wiki** — List all wiki pages, optionally filtered by category (entity/concept/timeline/synthesis).
83
+ - **wiki_search** — BM25 search across all wiki pages. Returns ranked results with previews.
84
+ - **query_wiki** — One-stop Q&A: searches wiki, synthesises an answer, returns source citations.
85
+ - **synthesize_answer** — Generate a markdown synthesis from a list of specific wiki page IDs.
86
+ - **save_answer_as_page** — Persist a synthesised answer back into the wiki (knowledge compounding).
87
+
88
+ ## Health & Guidance Tools
89
+
90
+ - **lint_wiki** — Health check: orphan pages, broken refs, stale content, metadata gaps. Returns a 0–100 health score.
91
+ - **get_schema_guidance** — Analyse what wiki pages should exist based on the schema and current state.
92
+ - **preview_generation** — Preview what a tool will do before running it.
93
+
94
+ ## Common Workflows
95
+
96
+ ### First time — understand the codebase
97
+ \`\`\`
98
+ list_modules({ path: "${projectDir}" })
99
+ → read the language breakdown and dependency map
100
+ → write_spec each important module
101
+ \`\`\`
102
+
103
+ ### Ongoing — answer a question
104
+ \`\`\`
105
+ query_wiki({ project_path: "${projectDir}", question: "How does authentication work?" })
106
+ → save_answer_as_page if the answer is worth keeping
107
+ \`\`\`
108
+
109
+ ### Maintenance — check wiki health
110
+ \`\`\`
111
+ lint_wiki({ project_path: "${projectDir}" })
112
+ → fix orphans and broken refs
113
+ \`\`\`
114
+
115
+ ## Storage Layout
116
+
117
+ \`\`\`
118
+ .docuflow/
119
+ ├── specs/ Legacy spec files written by write_spec
120
+ ├── wiki/ LLM-generated wiki pages
121
+ │ ├── entities/ Named things (services, APIs, databases)
122
+ │ ├── concepts/ Design patterns, principles, integrations
123
+ │ ├── timelines/ Chronological pages
124
+ │ └── syntheses/ Cross-cutting synthesis pages
125
+ ├── sources/ Raw input files for ingest_source
126
+ ├── schema.md Wiki configuration (edit to customise)
127
+ ├── index.md Auto-maintained catalog
128
+ └── log.md Operation log
129
+ \`\`\`
130
+ `;
131
+ }
132
+ async function writeClaudeMd(projectDir) {
133
+ const claudeMdPath = node_path_1.default.join(projectDir, "CLAUDE.md");
134
+ const newSection = buildClaudeMd(projectDir);
135
+ if (node_fs_1.default.existsSync(claudeMdPath)) {
136
+ const existing = await promises_1.default.readFile(claudeMdPath, "utf8");
137
+ if (existing.includes("DocuFlow")) {
138
+ // Already has DocuFlow section — replace it
139
+ const withoutDocuflow = existing.replace(/\n?# DocuFlow[\s\S]*/, "").trimEnd();
140
+ await promises_1.default.writeFile(claudeMdPath, withoutDocuflow + "\n\n" + newSection, "utf8");
141
+ }
142
+ else {
143
+ // Append to existing CLAUDE.md
144
+ await promises_1.default.appendFile(claudeMdPath, "\n\n" + newSection, "utf8");
145
+ }
146
+ }
147
+ else {
148
+ await promises_1.default.writeFile(claudeMdPath, newSection, "utf8");
149
+ }
150
+ }
60
151
  async function run() {
61
152
  const configPath = getClaudeDesktopConfigPath();
62
153
  const serverBin = resolveServerBin();
@@ -76,7 +167,8 @@ async function run() {
76
167
  await promises_1.default.mkdir(node_path_1.default.dirname(configPath), { recursive: true });
77
168
  await promises_1.default.writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
78
169
  // Create .docuflow/ directory structure
79
- const docuflowDir = node_path_1.default.join(process.cwd(), ".docuflow");
170
+ const projectDir = process.cwd();
171
+ const docuflowDir = node_path_1.default.join(projectDir, ".docuflow");
80
172
  const specsDir = node_path_1.default.join(docuflowDir, "specs");
81
173
  const wikiDir = node_path_1.default.join(docuflowDir, "wiki");
82
174
  const sourcesDir = node_path_1.default.join(docuflowDir, "sources");
@@ -94,6 +186,8 @@ async function run() {
94
186
  await copyTemplateFile("schema.md", node_path_1.default.join(docuflowDir, "schema.md"));
95
187
  await copyTemplateFile("index.md", node_path_1.default.join(docuflowDir, "index.md"));
96
188
  await copyTemplateFile("log.md", node_path_1.default.join(docuflowDir, "log.md"));
189
+ // Generate CLAUDE.md so Claude Code picks up DocuFlow automatically
190
+ await writeClaudeMd(projectDir);
97
191
  // Add .docuflow/ to .gitignore if present and not already listed
98
192
  const gitignorePath = node_path_1.default.join(process.cwd(), ".gitignore");
99
193
  if (node_fs_1.default.existsSync(gitignorePath)) {
@@ -117,6 +211,10 @@ async function run() {
117
211
  console.log(` ├── index.md (auto-maintained catalog)`);
118
212
  console.log(` └── log.md (operation log)`);
119
213
  console.log("");
214
+ console.log("📝 CLAUDE.md:");
215
+ console.log(` Generated at: ${node_path_1.default.join(projectDir, "CLAUDE.md")}`);
216
+ console.log(` Claude Code will automatically read DocuFlow tool instructions.`);
217
+ console.log("");
120
218
  console.log("🔧 MCP Configuration:");
121
219
  console.log(` MCP key: mcpServers.docuflow`);
122
220
  console.log(` Config file: ${configPath}`);
@@ -7,6 +7,7 @@ exports.run = run;
7
7
  const promises_1 = __importDefault(require("node:fs/promises"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
9
  const node_os_1 = __importDefault(require("node:os"));
10
+ const node_fs_1 = __importDefault(require("node:fs"));
10
11
  function getClaudeDesktopConfigPath() {
11
12
  const platform = process.platform;
12
13
  if (platform === "darwin") {
@@ -17,8 +18,33 @@ function getClaudeDesktopConfigPath() {
17
18
  }
18
19
  return node_path_1.default.join(node_os_1.default.homedir(), ".config", "Claude", "claude_desktop_config.json");
19
20
  }
21
+ async function readLastIngestDate(docuDir) {
22
+ try {
23
+ const log = await promises_1.default.readFile(node_path_1.default.join(docuDir, "log.md"), "utf8");
24
+ const match = log.match(/\[(\d{4}-\d{2}-\d{2}[^\]]*)\]\s+ingest/);
25
+ return match ? match[1] : "never";
26
+ }
27
+ catch {
28
+ return "never";
29
+ }
30
+ }
31
+ async function countWikiPages(docuDir) {
32
+ const counts = { entities: 0, concepts: 0, timelines: 0, syntheses: 0 };
33
+ for (const cat of Object.keys(counts)) {
34
+ try {
35
+ const files = await promises_1.default.readdir(node_path_1.default.join(docuDir, "wiki", cat));
36
+ counts[cat] = files.filter((f) => f.endsWith(".md")).length;
37
+ }
38
+ catch {
39
+ // Directory may not exist
40
+ }
41
+ }
42
+ return counts;
43
+ }
20
44
  async function run() {
21
45
  const configPath = getClaudeDesktopConfigPath();
46
+ const projectDir = process.cwd();
47
+ const docuDir = node_path_1.default.join(projectDir, ".docuflow");
22
48
  // Check MCP registration
23
49
  let registered = false;
24
50
  try {
@@ -31,21 +57,73 @@ async function run() {
31
57
  }
32
58
  // Count spec files
33
59
  let specCount = 0;
34
- const specsDir = node_path_1.default.join(process.cwd(), ".docuflow", "specs");
35
60
  try {
36
- const entries = await promises_1.default.readdir(specsDir);
37
- specCount = entries.filter(e => e.endsWith(".md")).length;
61
+ const entries = await promises_1.default.readdir(node_path_1.default.join(docuDir, "specs"));
62
+ specCount = entries.filter((e) => e.endsWith(".md")).length;
38
63
  }
39
64
  catch {
40
65
  // .docuflow/specs doesn't exist
41
66
  }
42
- console.log("Docuflow status");
43
- console.log("───────────────────────────────");
44
- console.log(` MCP registered: ${registered ? "yes" : "no"}`);
45
- console.log(` Specs written: ${specCount}`);
46
- console.log(` Config file: ${configPath}`);
67
+ // Count sources
68
+ let sourceCount = 0;
69
+ try {
70
+ const entries = await promises_1.default.readdir(node_path_1.default.join(docuDir, "sources"));
71
+ sourceCount = entries.filter((e) => e.endsWith(".md") || e.endsWith(".txt")).length;
72
+ }
73
+ catch {
74
+ // .docuflow/sources doesn't exist
75
+ }
76
+ // Check for CLAUDE.md
77
+ const claudeMdExists = node_fs_1.default.existsSync(node_path_1.default.join(projectDir, "CLAUDE.md"));
78
+ // Count wiki pages per category
79
+ const wikiCounts = await countWikiPages(docuDir);
80
+ const totalWikiPages = Object.values(wikiCounts).reduce((a, b) => a + b, 0);
81
+ // Last ingest date
82
+ const lastIngest = await readLastIngestDate(docuDir);
83
+ // Get CLI version from package.json
84
+ let version = "unknown";
85
+ try {
86
+ const pkgPath = require.resolve("@doquflow/cli/package.json");
87
+ const pkg = JSON.parse(await promises_1.default.readFile(pkgPath, "utf8"));
88
+ version = pkg.version;
89
+ }
90
+ catch {
91
+ try {
92
+ const pkgPath = node_path_1.default.resolve(__dirname, "..", "..", "package.json");
93
+ const pkg = JSON.parse(await promises_1.default.readFile(pkgPath, "utf8"));
94
+ version = pkg.version;
95
+ }
96
+ catch {
97
+ // Can't resolve version
98
+ }
99
+ }
100
+ console.log("\nDocuflow status");
101
+ console.log("───────────────────────────────────────────");
102
+ console.log(` Version: ${version}`);
103
+ console.log(` MCP registered: ${registered ? "✓ yes" : "✗ no"}`);
104
+ console.log(` CLAUDE.md: ${claudeMdExists ? "✓ present" : "✗ missing"}`);
105
+ console.log(` Config file: ${configPath}`);
106
+ console.log("");
107
+ console.log(" Specs written: " + specCount);
108
+ console.log(" Sources: " + sourceCount);
109
+ console.log(" Last ingest: " + lastIngest);
110
+ console.log("");
111
+ console.log(" Wiki pages: " + totalWikiPages + " total");
112
+ if (totalWikiPages > 0) {
113
+ console.log(` entities: ${wikiCounts.entities}`);
114
+ console.log(` concepts: ${wikiCounts.concepts}`);
115
+ console.log(` syntheses: ${wikiCounts.syntheses}`);
116
+ console.log(` timelines: ${wikiCounts.timelines}`);
117
+ }
118
+ console.log("───────────────────────────────────────────");
47
119
  if (!registered) {
48
- console.log("");
49
- console.log(' Run "docuflow init" to register.');
120
+ console.log('\n ⚠ Run "docuflow init" to register MCP server.');
121
+ }
122
+ if (!claudeMdExists) {
123
+ console.log('\n ⚠ Run "docuflow init" to generate CLAUDE.md.');
124
+ }
125
+ if (totalWikiPages === 0 && sourceCount === 0) {
126
+ console.log('\n 💡 Run "docuflow suggest" to see what to document first.');
50
127
  }
128
+ console.log();
51
129
  }
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.run = run;
7
+ const promises_1 = __importDefault(require("node:fs/promises"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const node_fs_1 = __importDefault(require("node:fs"));
10
+ const DOMAIN_SUGGESTIONS = {
11
+ "Code/Architecture": [
12
+ { priority: 1, type: "wiki_page", title: "System Architecture Overview", reason: "High-level view of how all components fit together", prompt: "Ingest the README or architecture doc, then ask: 'Create a System Architecture Overview page in the wiki'" },
13
+ { priority: 2, type: "wiki_page", title: "Core Architectural Patterns", reason: "Design patterns used throughout the codebase", prompt: "Ask Claude: 'Scan the codebase with list_modules and identify the core architectural patterns'" },
14
+ { priority: 3, type: "wiki_page", title: "Module Dependencies", reason: "Which modules depend on which — risky to change without knowing", prompt: "Ask Claude: 'Use list_modules to build a module dependency map and write it as a wiki page'" },
15
+ { priority: 4, type: "wiki_page", title: "Database Schema Overview", reason: "Tables, relationships, and ownership by module", prompt: "Ask Claude: 'Scan the project for DB tables using list_modules and create a Database Schema wiki page'" },
16
+ { priority: 5, type: "starter_question", title: "What modules are most connected?", reason: "Identifies the highest-risk code to change", prompt: "Ask Claude: 'Use list_modules on this project and tell me which files have the most dependencies'" },
17
+ ],
18
+ Research: [
19
+ { priority: 1, type: "wiki_page", title: "Research Domain Overview", reason: "Big picture of the research area", prompt: "Ingest your main survey paper, then ask: 'Create a Research Domain Overview page'" },
20
+ { priority: 2, type: "wiki_page", title: "Key Findings & Synthesis", reason: "Major discoveries and insights", prompt: "Ask Claude: 'After ingesting my sources, synthesize the key findings into a wiki page'" },
21
+ { priority: 3, type: "wiki_page", title: "Areas of Contradiction", reason: "Where researchers disagree — critical to track", prompt: "Ask Claude: 'Run lint_wiki and identify any contradictions, then create an Areas of Contradiction page'" },
22
+ { priority: 4, type: "wiki_page", title: "Open Research Questions", reason: "What's still unknown in this domain", prompt: "Ask Claude: 'Based on ingested sources, what questions remain unanswered?'" },
23
+ { priority: 5, type: "starter_question", title: "What are the most cited entities?", reason: "Shows which concepts are most important", prompt: "Ask Claude: 'Which entities appear most often across all ingested sources?'" },
24
+ ],
25
+ Business: [
26
+ { priority: 1, type: "wiki_page", title: "Market Overview", reason: "Big picture of the market and competitive landscape", prompt: "Ingest market research docs, then ask: 'Create a Market Overview wiki page'" },
27
+ { priority: 2, type: "wiki_page", title: "Competitive Analysis", reason: "How competitors differ — essential strategic context", prompt: "Ask Claude: 'After ingesting competitor info, create a Competitive Analysis synthesis page'" },
28
+ { priority: 3, type: "wiki_page", title: "Market Opportunities", reason: "Gaps and growth areas to track", prompt: "Ask Claude: 'Identify market opportunities from ingested sources and create a wiki page'" },
29
+ { priority: 4, type: "wiki_page", title: "Key Players", reason: "Entities (companies, people) to track over time", prompt: "Ask Claude: 'Create an entity page for each key competitor found in sources'" },
30
+ { priority: 5, type: "starter_question", title: "Who are the key players in this market?", reason: "First question to anchor the wiki", prompt: "Ask Claude: 'List the key companies and people from ingested market data'" },
31
+ ],
32
+ Personal: [
33
+ { priority: 1, type: "wiki_page", title: "Learning Goals", reason: "Anchors everything else in the wiki", prompt: "Ask Claude: 'Create a Learning Goals page from my notes in .docuflow/sources/'" },
34
+ { priority: 2, type: "wiki_page", title: "Key Personal Insights", reason: "Preserve insights before they fade", prompt: "Ask Claude: 'Ingest my notes and create a Key Insights synthesis page'" },
35
+ { priority: 3, type: "wiki_page", title: "Key Resources", reason: "Books, courses, links to revisit", prompt: "Ask Claude: 'Extract and create an entity page for each key resource mentioned in my notes'" },
36
+ { priority: 4, type: "wiki_page", title: "Action Items & Next Steps", reason: "Turns knowledge into action", prompt: "Ask Claude: 'What action items can you find across my wiki pages? Create a synthesis page'" },
37
+ { priority: 5, type: "starter_question", title: "What do I already know about this topic?", reason: "Baseline before adding more sources", prompt: "Ask Claude: 'Query the wiki for what I know about [your topic]'" },
38
+ ],
39
+ General: [
40
+ { priority: 1, type: "action", title: "Add your first source file", reason: "Nothing can be ingested until you put a file in .docuflow/sources/", prompt: "Copy your README, main doc, or any markdown file into .docuflow/sources/" },
41
+ { priority: 2, type: "wiki_page", title: "Overview / Summary page", reason: "A starting page that links to everything else", prompt: "Ask Claude: 'Ingest my first source and create an overview synthesis page'" },
42
+ { priority: 3, type: "starter_question", title: "What are the key entities in this domain?", reason: "Gets the wiki started with real content", prompt: "Ask Claude: 'After ingesting my first source, what are the key entities?'" },
43
+ { priority: 4, type: "wiki_page", title: "Key Concepts", reason: "Important ideas worth preserving", prompt: "Ask Claude: 'Create concept pages for the top 5 ideas from ingested sources'" },
44
+ { priority: 5, type: "action", title: "Run get_schema_guidance", reason: "DocuFlow will tell you what's missing based on your domain", prompt: "Ask Claude: 'Run get_schema_guidance on my project and show what pages are recommended'" },
45
+ ],
46
+ };
47
+ function detectDomain(schemaContent) {
48
+ if (/Architecture|Code|codebase|microservice|API/i.test(schemaContent))
49
+ return "Code/Architecture";
50
+ if (/Research|paper|findings|literature/i.test(schemaContent))
51
+ return "Research";
52
+ if (/Business|market|competitor|revenue/i.test(schemaContent))
53
+ return "Business";
54
+ if (/Personal|learning|goal|habit/i.test(schemaContent))
55
+ return "Personal";
56
+ return "General";
57
+ }
58
+ async function countWikiPages(docuDir) {
59
+ const counts = { entities: 0, concepts: 0, timelines: 0, syntheses: 0 };
60
+ for (const cat of Object.keys(counts)) {
61
+ try {
62
+ const files = await promises_1.default.readdir(node_path_1.default.join(docuDir, "wiki", cat));
63
+ counts[cat] = files.filter((f) => f.endsWith(".md")).length;
64
+ }
65
+ catch {
66
+ // Directory may not exist
67
+ }
68
+ }
69
+ return counts;
70
+ }
71
+ async function countSources(docuDir) {
72
+ try {
73
+ const files = await promises_1.default.readdir(node_path_1.default.join(docuDir, "sources"));
74
+ return files.filter((f) => f.endsWith(".md") || f.endsWith(".txt")).length;
75
+ }
76
+ catch {
77
+ return 0;
78
+ }
79
+ }
80
+ async function run() {
81
+ const projectDir = process.cwd();
82
+ const docuDir = node_path_1.default.join(projectDir, ".docuflow");
83
+ if (!node_fs_1.default.existsSync(docuDir)) {
84
+ console.log("⚠ DocuFlow not initialised in this directory.");
85
+ console.log(' Run "docuflow init" first.\n');
86
+ return;
87
+ }
88
+ // Detect domain from schema
89
+ let domain = "General";
90
+ try {
91
+ const schema = await promises_1.default.readFile(node_path_1.default.join(docuDir, "schema.md"), "utf8");
92
+ domain = detectDomain(schema);
93
+ }
94
+ catch {
95
+ // No schema yet — fall back to General
96
+ }
97
+ const [pageCounts, sourceCount] = await Promise.all([
98
+ countWikiPages(docuDir),
99
+ countSources(docuDir),
100
+ ]);
101
+ const totalPages = Object.values(pageCounts).reduce((a, b) => a + b, 0);
102
+ console.log(`\n💡 DocuFlow Suggestions — ${domain} domain\n`);
103
+ console.log(` Current wiki: ${totalPages} pages | ${sourceCount} source(s) ingested\n`);
104
+ if (totalPages === 0 && sourceCount === 0) {
105
+ console.log("🌱 Your wiki is empty. Here's where to start:\n");
106
+ }
107
+ else if (totalPages < 10) {
108
+ console.log("📚 Wiki is growing. Recommended next pages:\n");
109
+ }
110
+ else {
111
+ console.log("✅ Good coverage. Here's what could be stronger:\n");
112
+ }
113
+ const suggestions = DOMAIN_SUGGESTIONS[domain] ?? DOMAIN_SUGGESTIONS.General;
114
+ for (const s of suggestions) {
115
+ const icon = s.type === "action" ? "▶" : s.type === "starter_question" ? "❓" : "📄";
116
+ console.log(` ${s.priority}. ${icon} ${s.title}`);
117
+ console.log(` ${s.reason}`);
118
+ if (s.prompt) {
119
+ console.log(` → ${s.prompt}`);
120
+ }
121
+ console.log();
122
+ }
123
+ console.log("─────────────────────────────────────────────────────");
124
+ console.log("Quick start prompts for Claude:\n");
125
+ console.log(` • "Scan the project at ${projectDir} with list_modules"`);
126
+ console.log(` • "Show me get_schema_guidance for ${projectDir}"`);
127
+ console.log(` • "What wiki pages exist? Run list_wiki on ${projectDir}"`);
128
+ console.log(` • "What should I document first in this project?"`);
129
+ console.log();
130
+ }
package/dist/index.js CHANGED
@@ -33,16 +33,26 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  return result;
34
34
  };
35
35
  })();
36
- const [, , cmd] = process.argv;
36
+ const [, , cmd, flag] = process.argv;
37
37
  if (cmd === 'init') {
38
- Promise.resolve().then(() => __importStar(require('./commands/init'))).then(m => m.run());
38
+ if (flag === '--interactive' || flag === '-i') {
39
+ Promise.resolve().then(() => __importStar(require('./commands/init-interactive'))).then(m => m.runInteractive());
40
+ }
41
+ else {
42
+ Promise.resolve().then(() => __importStar(require('./commands/init'))).then(m => m.run());
43
+ }
39
44
  }
40
45
  else if (cmd === 'status') {
41
46
  Promise.resolve().then(() => __importStar(require('./commands/status'))).then(m => m.run());
42
47
  }
48
+ else if (cmd === 'suggest') {
49
+ Promise.resolve().then(() => __importStar(require('./commands/suggest'))).then(m => m.run());
50
+ }
43
51
  else {
44
- console.log('Usage: npx @doquflow/cli <init|status>');
52
+ console.log('Usage: npx @doquflow/cli <command>');
45
53
  console.log('');
46
- console.log(' init Register Docuflow MCP server in Claude Desktop config');
47
- console.log(' status Show spec count and MCP registration status');
54
+ console.log(' init Register Docuflow MCP and generate CLAUDE.md');
55
+ console.log(' init --interactive Interactive setup wizard (choose domain, project name)');
56
+ console.log(' status Show wiki health, page counts, and MCP status');
57
+ console.log(' suggest Show what to document first (domain-specific guidance)');
48
58
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doquflow/cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "CLI for setting up Docuflow in your project",
5
5
  "author": "Docuflow <hello@doquflows.dev>",
6
6
  "license": "MIT",
@@ -30,7 +30,7 @@
30
30
  "build": "tsc"
31
31
  },
32
32
  "dependencies": {
33
- "@doquflow/server": "0.3.0"
33
+ "@doquflow/server": "0.4.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "^22.0.0",