@doquflow/server 1.6.0 → 2.0.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.
@@ -1,89 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ENTITY_STOPLIST = void 0;
4
- /**
5
- * Stop-list for wiki entity extraction.
6
- * Any candidate whose normalized form appears here is rejected as a generic term
7
- * that adds noise without semantic value.
8
- *
9
- * Applied as single-word match AND whole-phrase match. Multi-word phrases
10
- * where every word is on this list are also rejected (see ruleStopList).
11
- */
12
- exports.ENTITY_STOPLIST = new Set([
13
- // Generic quantifiers / determiners
14
- "any", "all", "some", "each", "every", "one", "two", "three", "four", "five",
15
- "none", "both", "either", "other", "another", "several", "many", "few",
16
- // Conjunctions / prepositions / filler / connectors
17
- "the", "and", "or", "for", "with", "from", "into", "onto", "over", "under",
18
- "then", "when", "while", "where", "which", "what", "who", "why", "how",
19
- "that", "this", "these", "those", "here", "there", "of", "in", "on", "at",
20
- "to", "by", "as", "is", "are", "was", "were", "be", "been", "being",
21
- // Modal / auxiliary verbs
22
- "can", "will", "shall", "would", "could", "should", "must", "may", "might",
23
- "also", "just", "only", "even", "already", "still", "yet", "more",
24
- // Boolean / status tokens
25
- "true", "false", "yes", "no", "ok", "done", "todo",
26
- // Common vague action words
27
- "add", "added", "remove", "removed", "update", "updated",
28
- "change", "changed", "fix", "fixed", "use", "used", "get", "set",
29
- "allow", "allowed", "block", "blocked", "enable", "enabled", "disable", "disabled",
30
- "create", "created", "build", "built", "run", "ran", "make", "made",
31
- "show", "shows", "display", "displayed", "include", "included",
32
- // Generic noun noise
33
- "active", "audience", "behavior", "behaviour", "benefits", "binary",
34
- "append", "approval", "audit", "auditable",
35
- "note", "notes", "type", "types", "item", "items", "list", "value", "values",
36
- "option", "options", "example", "examples", "result", "results",
37
- "output", "outputs", "input", "inputs", "data", "info", "information",
38
- "step", "steps", "section", "sections", "part", "parts", "content",
39
- // Section-heading boilerplate (single words)
40
- "architecture", "overview", "purpose", "documentation", "installation",
41
- "commands", "components", "configuration", "management", "registration",
42
- "views", "view", "iteration", "iterations",
43
- "summary", "introduction", "background", "context", "scope", "rationale",
44
- "goals", "goal", "motivation", "definition", "definitions", "terminology",
45
- "implementation", "design", "approach", "methodology", "method", "methods",
46
- "usage", "setup", "tutorial", "guide", "guides", "reference",
47
- "requirements", "dependencies", "prerequisites", "features", "feature",
48
- "categories", "category", "kind", "kinds",
49
- "workflow", "workflows", "pipeline", "pipelines",
50
- "system", "systems", "module", "modules", "package", "packages",
51
- "service", "services", "interface", "interfaces", "layer", "layers",
52
- "support", "supports", "supported", "available", "current",
53
- // Common section adjectives (combined with stop nouns → all-stop phrase rejected)
54
- "key", "core", "main", "primary", "secondary", "general", "basic", "advanced",
55
- "common", "typical", "standard", "default", "custom", "specific", "generic",
56
- "new", "old", "next", "previous", "first", "last", "final", "initial",
57
- // Doc-structure terms
58
- "title", "abstract", "outline", "table", "figure", "diagram", "appendix",
59
- "footnote", "footnotes", "see", "above", "below",
60
- // Common project section phrases (multi-word, exact match)
61
- "getting started", "next steps", "key components", "key commands",
62
- "core modules", "core components", "core types", "tech stack",
63
- "technology stack", "use case", "use cases", "see also", "edge cases",
64
- "acceptance criteria", "test scenarios", "testing results",
65
- "implementation status", "implementation steps", "files to touch",
66
- "format options", "format purity", "data flow", "data storage",
67
- "entry point", "output includes", "step by step",
68
- "command pattern", "tool pattern", "document type", "release history",
69
- "design principles", "security considerations",
70
- "global flags", "environment variables", "flag normalization",
71
- "filename validation", "commit deduplication", "commit message format",
72
- "create update", "find contradictions", "find gaps", "find orphans", "find stale",
73
- "build pipeline", "ci cd", "ci cd pipeline", "github actions workflow",
74
- "github actions integration", "version controlled", "version injection",
75
- "deployment to release repo", "readme integration",
76
- "lessons learned applied to docuflow", "specific wiki pages for docuflow",
77
- "wiki maintenance for docuflow", "wiki pipeline tools", "codebase scanner tools",
78
- "health guidance tools", "tool categories summary", "package responsibilities",
79
- "component architecture", "monorepo overview", "package architecture",
80
- "phase 2 testing", "initial setup", "ingest workflow", "query workflow",
81
- "lint workflow", "related entities", "agent integration",
82
- "integration with docuflow", "mcp registration",
83
- "project context", "project auto discovery", "provider detection",
84
- "silent fallback warning", "reviewer verdict format", "task spec format",
85
- "reusable skill", "supported languages",
86
- "what it detects", "what it does", "what it shows", "what starts",
87
- "concepts ideas", "entities things", "syntheses analyses", "timelines events",
88
- "graph tool", "format options",
89
- ]);
package/dist/extractor.js DELETED
@@ -1,171 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.extract = extract;
4
- function uniq(arr) {
5
- return Array.from(new Set(arr.filter((s) => s && s.length > 0)));
6
- }
7
- function collect(re, content, group = 1) {
8
- const out = [];
9
- let m;
10
- while ((m = re.exec(content)) !== null) {
11
- if (m[group])
12
- out.push(m[group]);
13
- }
14
- return out;
15
- }
16
- const RE_CLASS = /(?:abstract\s+|sealed\s+|partial\s+|public\s+|private\s+|protected\s+|internal\s+|static\s+)*(?:class|interface|struct|enum|record)\s+([A-Z]\w*)/g;
17
- const RE_FUNC_KW = /(?:public|private|protected|internal|static|async|override|function|def|fn|sub)\s+(?:[\w<>\[\],?\s]+?\s+)?([A-Za-z_]\w*)\s*\(/g;
18
- const RE_FUNC_ARROW = /\b([A-Za-z_]\w*)\s*=\s*(?:async\s*)?\([^)]*\)\s*=>/g;
19
- const RE_METHOD_TS = /^\s*(?:public|private|protected|static|async|readonly|\s)*([a-z_]\w*)\s*\([^)]*\)\s*[:{]/gm;
20
- const RE_USING = /\busing\s+([\w.]+)\s*;/g;
21
- const RE_IMPORT_FROM = /\bimport\s+(?:[\w*${}\s,]+\s+from\s+)?['"]([^'"]+)['"]/g;
22
- const RE_REQUIRE = /\brequire\(\s*['"]([^'"]+)['"]\s*\)/g;
23
- const RE_DECORATOR = /@(Injectable|Component|Inject|Service|Module|Directive|Pipe|NgModule|Controller)\b/g;
24
- const RE_NEW_CLASS = /\bnew\s+([A-Z]\w*)\s*\(/g;
25
- // Standard SQL FROM/JOIN/INTO/UPDATE/DELETE patterns.
26
- const RE_SQL_TABLE = /(?:\bFROM|\bJOIN|\bINTO|\bUPDATE|\bDELETE\s+FROM|\bTABLE)\s+([A-Za-z_][\w.]*)/gi;
27
- // EF / ORM DbSet<T> declaration.
28
- const RE_DBSET = /\bDbSet<\s*([A-Z]\w*)\s*>/g;
29
- // Attribute-based table mapping: [Table("name")] and .Table("name")
30
- const RE_TABLE_ATTR = /\[Table\(\s*["']([^"']+)["']/g;
31
- const RE_TABLE_FLUENT = /\.Table\(\s*["']([^"']+)["']\s*\)/g;
32
- // EF DbContext property access: _db.Orders., context.Users., _repository.Items. etc.
33
- // Catches patterns like `_db.Orders.ToListAsync()`, `_context.Users.Find(id)`.
34
- const RE_EF_PROP = /\b(?:_?db|_?context|_?ctx|_?repository|_?repo)\s*\.\s*([A-Z]\w+)(?=[\s.(])/g;
35
- const RE_DOTNET_ROUTE = /\[(?:Route|Http(?:Get|Post|Put|Delete|Patch))\(\s*["']([^"']*)["']/g;
36
- const RE_MIN_API = /\bapp\.Map(?:Get|Post|Put|Delete|Patch)\s*\(\s*["']([^"']+)["']/g;
37
- const RE_EXPRESS = /\b(?:router|app)\.(?:get|post|put|delete|patch|use)\s*\(\s*['"]([^'"]+)['"]/g;
38
- const RE_NEST = /@(?:Get|Post|Put|Delete|Patch)\s*\(\s*['"]([^'"]+)['"]/g;
39
- const RE_NG_PATH = /\bpath\s*:\s*['"]([^'"]+)['"]/g;
40
- // Flask: @app.route('/path') @bp.route('/path')
41
- const RE_FLASK = /@\w+\.route\s*\(\s*['"]([^'"]+)['"]/g;
42
- // FastAPI / Flask-style: @app.get('/x') @router.post('/x')
43
- const RE_FASTAPI = /@(?:app|router|bp)\s*\.\s*(?:get|post|put|delete|patch)\s*\(\s*['"]([^'"]+)['"]/g;
44
- // Django: path('url/', view) url('pattern/', view)
45
- const RE_DJANGO = /\bpath\s*\(\s*['"]([^'"]+)['"]/g;
46
- const RE_CFG_CONNSTR = /\bConnectionStrings:([\w.]+)/g;
47
- const RE_PROCESS_ENV = /\bprocess\.env\.([A-Z_][A-Z0-9_]*)/g;
48
- const RE_DOTNET_ENV = /\bEnvironment\.GetEnvironmentVariable\(\s*["']([^"']+)["']/g;
49
- const RE_ICONFIG = /\bIConfiguration\b/g;
50
- const RE_APPSETTINGS = /\bappsettings(?:\.[A-Za-z0-9]+)?\.json\b/g;
51
- // ─── Go ─────────────────────────────────────────────────────────────────────
52
- // type FooBar struct | type FooBar interface
53
- const RE_GO_TYPE = /\btype\s+([A-Z]\w*)\s+(?:struct|interface)/g;
54
- // func FuncName( or func (recv *Type) MethodName(
55
- const RE_GO_FUNC = /\bfunc\s+(?:\([^)]+\)\s+)?([A-Za-z_]\w*)\s*\(/g;
56
- // import "pkg" or import ( "pkg" ) — individual quoted paths inside import blocks
57
- const RE_GO_IMPORT = /^\s+["']([^"'\s]+)["']\s*(?:\/\/.*)?$/gm;
58
- // os.Getenv("KEY") or os.LookupEnv("KEY")
59
- const RE_GO_ENV = /\bos\.(?:Getenv|LookupEnv)\s*\(\s*["']([A-Z_][A-Z0-9_]*)["']/g;
60
- // gorilla/mux, gin, chi, echo, stdlib: router.GET("/path", ...)
61
- const RE_GO_HTTP = /\b(?:r|router|e|mux|g|app)\s*\.\s*(?:HandleFunc|GET|POST|PUT|DELETE|PATCH|Handle|Any)\s*\(\s*["']([^"']+)["']/g;
62
- // GORM explicit table: db.Table("name")
63
- const RE_GO_GORM_TABLE = /\bdb\s*\.\s*Table\s*\(\s*["']([^"']+)["']/g;
64
- // ─── Ruby / Rails ────────────────────────────────────────────────────────────
65
- // class Foo or module Bar
66
- const RE_RUBY_CLASS = /\b(?:class|module)\s+([A-Z]\w*(?:::[A-Z]\w*)*)/g;
67
- // def method_name or def self.method_name
68
- const RE_RUBY_DEF = /^\s*def\s+(?:self\.)?([a-z_]\w*)/gm;
69
- // require 'gem' or require_relative '../path'
70
- const RE_RUBY_REQUIRE = /\brequire(?:_relative)?\s+["']([^"']+)["']/g;
71
- // ENV['KEY'] or ENV["KEY"]
72
- const RE_RUBY_ENV = /\bENV\s*\[\s*["']([A-Z_][A-Z0-9_]*)["']\s*\]/g;
73
- // Rails routes: get '/path', post '/path', resources :users, root 'home#index'
74
- const RE_RAILS_ROUTE = /^\s*(?:get|post|put|delete|patch|resources|resource|root)\s+["']([^"']+)["']/gm;
75
- // ActiveRecord associations: has_many :users, belongs_to :user
76
- const RE_AR_HAS = /\bhas_(?:many|one)\s+:(\w+)/g;
77
- const RE_AR_BELONGS = /\bbelongs_to\s+:(\w+)/g;
78
- // Explicit table name: self.table_name = 'table'
79
- const RE_AR_TABLE = /\bself\.table_name\s*=\s*["']([^"']+)["']/g;
80
- // SQL keywords and noise that the regex may pick up as table names.
81
- // Also strips single-letter hits (LINQ aliases: `from u in _db.Users` → u).
82
- const SQL_KEYWORD_NOISE = new Set([
83
- "select", "where", "set", "on", "as", "by", "in", "is", "not", "null",
84
- "and", "or", "top", "all", "any", "exists", "between", "like", "case",
85
- "when", "then", "else", "end", "with", "having", "group", "order",
86
- "asc", "desc", "distinct", "outer", "inner", "left", "right", "full",
87
- "cross", "natural", "values", "default", "primary", "key", "index",
88
- ]);
89
- // EF DbContext property names that are framework plumbing, not tables.
90
- const EF_NOISE = new Set([
91
- "SaveChanges", "SaveChangesAsync", "Entry", "Add", "AddRange", "Remove",
92
- "RemoveRange", "Update", "UpdateRange", "Attach", "Find", "FindAsync",
93
- "FromSqlRaw", "FromSqlInterpolated", "Database", "Model", "ChangeTracker",
94
- "Configuration", "ToList", "ToListAsync", "FirstOrDefault", "FirstOrDefaultAsync",
95
- "Where", "Any", "Count", "Include", "ThenInclude", "OrderBy", "GroupBy", "Select",
96
- ]);
97
- function cleanTableNames(names) {
98
- return names.filter((n) => {
99
- if (n.length < 2)
100
- return false;
101
- if (SQL_KEYWORD_NOISE.has(n.toLowerCase()))
102
- return false;
103
- if (EF_NOISE.has(n))
104
- return false;
105
- return true;
106
- });
107
- }
108
- function extract(content) {
109
- const classes = uniq([
110
- ...collect(new RegExp(RE_CLASS.source, "g"), content),
111
- ...collect(new RegExp(RE_GO_TYPE.source, "g"), content),
112
- ...collect(new RegExp(RE_RUBY_CLASS.source, "g"), content),
113
- ]);
114
- const functions = uniq([
115
- ...collect(new RegExp(RE_FUNC_KW.source, "g"), content),
116
- ...collect(new RegExp(RE_FUNC_ARROW.source, "g"), content),
117
- ...collect(new RegExp(RE_METHOD_TS.source, "gm"), content),
118
- ...collect(new RegExp(RE_GO_FUNC.source, "g"), content),
119
- ...collect(new RegExp(RE_RUBY_DEF.source, "gm"), content),
120
- ]).filter((n) => !["if", "for", "while", "switch", "catch", "return", "function"].includes(n));
121
- const dependencies = uniq([
122
- ...collect(new RegExp(RE_USING.source, "g"), content),
123
- ...collect(new RegExp(RE_IMPORT_FROM.source, "g"), content),
124
- ...collect(new RegExp(RE_REQUIRE.source, "g"), content),
125
- ...collect(new RegExp(RE_DECORATOR.source, "g"), content),
126
- ...collect(new RegExp(RE_NEW_CLASS.source, "g"), content),
127
- ...collect(new RegExp(RE_GO_IMPORT.source, "gm"), content),
128
- ...collect(new RegExp(RE_RUBY_REQUIRE.source, "g"), content),
129
- ]);
130
- const db_tables = uniq(cleanTableNames([
131
- ...collect(new RegExp(RE_SQL_TABLE.source, "gi"), content),
132
- ...collect(new RegExp(RE_DBSET.source, "g"), content),
133
- ...collect(new RegExp(RE_TABLE_ATTR.source, "g"), content),
134
- ...collect(new RegExp(RE_TABLE_FLUENT.source, "g"), content),
135
- ...collect(new RegExp(RE_EF_PROP.source, "g"), content),
136
- ...collect(new RegExp(RE_GO_GORM_TABLE.source, "g"), content),
137
- ...collect(new RegExp(RE_AR_HAS.source, "g"), content),
138
- ...collect(new RegExp(RE_AR_BELONGS.source, "g"), content),
139
- ...collect(new RegExp(RE_AR_TABLE.source, "g"), content),
140
- ]));
141
- const endpoints = uniq([
142
- ...collect(new RegExp(RE_DOTNET_ROUTE.source, "g"), content),
143
- ...collect(new RegExp(RE_MIN_API.source, "g"), content),
144
- ...collect(new RegExp(RE_EXPRESS.source, "g"), content),
145
- ...collect(new RegExp(RE_NEST.source, "g"), content),
146
- ...collect(new RegExp(RE_NG_PATH.source, "g"), content),
147
- ...collect(new RegExp(RE_FLASK.source, "g"), content),
148
- ...collect(new RegExp(RE_FASTAPI.source, "g"), content),
149
- ...collect(new RegExp(RE_DJANGO.source, "g"), content),
150
- ...collect(new RegExp(RE_GO_HTTP.source, "g"), content),
151
- ...collect(new RegExp(RE_RAILS_ROUTE.source, "gm"), content),
152
- ]);
153
- const config_refs = [];
154
- config_refs.push(...collect(new RegExp(RE_CFG_CONNSTR.source, "g"), content).map((s) => `ConnectionStrings:${s}`));
155
- config_refs.push(...collect(new RegExp(RE_PROCESS_ENV.source, "g"), content).map((s) => `process.env.${s}`));
156
- config_refs.push(...collect(new RegExp(RE_DOTNET_ENV.source, "g"), content));
157
- config_refs.push(...collect(new RegExp(RE_GO_ENV.source, "g"), content).map((s) => `os.Getenv(${s})`));
158
- config_refs.push(...collect(new RegExp(RE_RUBY_ENV.source, "g"), content).map((s) => `ENV[${s}]`));
159
- if (RE_ICONFIG.test(content))
160
- config_refs.push("IConfiguration");
161
- if (RE_APPSETTINGS.test(content))
162
- config_refs.push("appsettings.json");
163
- return {
164
- classes: uniq(classes),
165
- functions: uniq(functions),
166
- dependencies,
167
- db_tables,
168
- endpoints,
169
- config_refs: uniq(config_refs),
170
- };
171
- }
@@ -1,132 +0,0 @@
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.walk = walk;
7
- exports.isBinary = isBinary;
8
- exports.safeReadFile = safeReadFile;
9
- exports.ensureDir = ensureDir;
10
- exports.writeFileAtomic = writeFileAtomic;
11
- exports.readJsonIfExists = readJsonIfExists;
12
- const promises_1 = __importDefault(require("node:fs/promises"));
13
- const node_path_1 = __importDefault(require("node:path"));
14
- const SKIP_DIRS = new Set([
15
- "node_modules",
16
- "vendor",
17
- ".git",
18
- ".svn",
19
- ".hg",
20
- "dist",
21
- "build",
22
- "bin",
23
- "obj",
24
- ".docuflow",
25
- ".next",
26
- ".nuxt",
27
- "out",
28
- "target",
29
- ".venv",
30
- "venv",
31
- "__pycache__",
32
- ]);
33
- const SKIP_FILE_PATTERNS = [
34
- /\.min\.js$/i,
35
- /\.min\.css$/i,
36
- /\.map$/i,
37
- /\.lock$/i,
38
- /package-lock\.json$/i,
39
- ];
40
- const MAX_FILE_BYTES = 300 * 1024;
41
- async function walk(root) {
42
- const files = [];
43
- const skipped = [];
44
- const absRoot = node_path_1.default.resolve(root);
45
- async function recurse(dir) {
46
- let entries;
47
- try {
48
- entries = await promises_1.default.readdir(dir, { withFileTypes: true });
49
- }
50
- catch (e) {
51
- skipped.push({ path: dir, reason: `readdir failed: ${e.message}` });
52
- return;
53
- }
54
- for (const entry of entries) {
55
- const full = node_path_1.default.join(dir, entry.name);
56
- if (entry.isDirectory()) {
57
- if (SKIP_DIRS.has(entry.name))
58
- continue;
59
- await recurse(full);
60
- }
61
- else if (entry.isFile()) {
62
- if (SKIP_FILE_PATTERNS.some((re) => re.test(entry.name))) {
63
- skipped.push({ path: full, reason: "skipped by pattern" });
64
- continue;
65
- }
66
- let stat;
67
- try {
68
- stat = await promises_1.default.stat(full);
69
- }
70
- catch (e) {
71
- skipped.push({ path: full, reason: `stat failed: ${e.message}` });
72
- continue;
73
- }
74
- if (stat.size > MAX_FILE_BYTES) {
75
- skipped.push({ path: full, reason: `file >300KB (${stat.size} bytes)` });
76
- continue;
77
- }
78
- files.push({ path: full, size: stat.size });
79
- }
80
- }
81
- }
82
- try {
83
- const stat = await promises_1.default.stat(absRoot);
84
- if (!stat.isDirectory()) {
85
- skipped.push({ path: absRoot, reason: "not a directory" });
86
- return { files, skipped };
87
- }
88
- }
89
- catch (e) {
90
- skipped.push({ path: absRoot, reason: `root stat failed: ${e.message}` });
91
- return { files, skipped };
92
- }
93
- await recurse(absRoot);
94
- return { files, skipped };
95
- }
96
- function isBinary(buf) {
97
- const len = Math.min(buf.length, 512);
98
- for (let i = 0; i < len; i++) {
99
- if (buf[i] === 0)
100
- return true;
101
- }
102
- return false;
103
- }
104
- async function safeReadFile(filePath) {
105
- try {
106
- const buf = await promises_1.default.readFile(filePath);
107
- if (isBinary(buf)) {
108
- return { size: buf.length, binary: true };
109
- }
110
- return { content: buf.toString("utf8"), size: buf.length };
111
- }
112
- catch (e) {
113
- return { size: 0, error: e.message };
114
- }
115
- }
116
- async function ensureDir(dir) {
117
- await promises_1.default.mkdir(dir, { recursive: true });
118
- }
119
- async function writeFileAtomic(filePath, content) {
120
- await ensureDir(node_path_1.default.dirname(filePath));
121
- await promises_1.default.writeFile(filePath, content, "utf8");
122
- return Buffer.byteLength(content, "utf8");
123
- }
124
- async function readJsonIfExists(filePath) {
125
- try {
126
- const txt = await promises_1.default.readFile(filePath, "utf8");
127
- return JSON.parse(txt);
128
- }
129
- catch {
130
- return null;
131
- }
132
- }
@@ -1,58 +0,0 @@
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.extensionToLanguage = extensionToLanguage;
7
- const node_path_1 = __importDefault(require("node:path"));
8
- const EXT_MAP = {
9
- ".cs": "csharp",
10
- ".vb": "vbnet",
11
- ".fs": "fsharp",
12
- ".ts": "typescript",
13
- ".tsx": "typescript",
14
- ".js": "javascript",
15
- ".jsx": "javascript",
16
- ".mjs": "javascript",
17
- ".cjs": "javascript",
18
- ".php": "php",
19
- ".java": "java",
20
- ".py": "python",
21
- ".rb": "ruby",
22
- ".go": "go",
23
- ".rs": "rust",
24
- ".kt": "kotlin",
25
- ".swift": "swift",
26
- ".html": "html",
27
- ".htm": "html",
28
- ".cshtml": "razor",
29
- ".razor": "razor",
30
- ".vue": "vue",
31
- ".css": "css",
32
- ".scss": "scss",
33
- ".sass": "sass",
34
- ".less": "less",
35
- ".json": "json",
36
- ".xml": "xml",
37
- ".yml": "yaml",
38
- ".yaml": "yaml",
39
- ".sql": "sql",
40
- ".sh": "shell",
41
- ".bash": "shell",
42
- ".ps1": "powershell",
43
- ".md": "markdown",
44
- ".c": "c",
45
- ".h": "c",
46
- ".cpp": "cpp",
47
- ".hpp": "cpp",
48
- ".cc": "cpp",
49
- };
50
- function extensionToLanguage(filePath) {
51
- const base = node_path_1.default.basename(filePath).toLowerCase();
52
- // Angular pattern detection — checked first, before generic .ts.
53
- if (base.endsWith(".component.ts") || base.endsWith(".service.ts") || base.endsWith(".module.ts") || base.endsWith(".directive.ts") || base.endsWith(".pipe.ts") || base.endsWith(".guard.ts")) {
54
- return "angular";
55
- }
56
- const ext = node_path_1.default.extname(base);
57
- return EXT_MAP[ext] ?? "unknown";
58
- }
@@ -1,189 +0,0 @@
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.synthesizeAnswer = synthesizeAnswer;
7
- const node_path_1 = __importDefault(require("node:path"));
8
- const filesystem_1 = require("../filesystem");
9
- /**
10
- * Extract key sentences from content that relate to the query
11
- */
12
- function extractRelevantSentences(content, queryTerms, maxSentences = 3) {
13
- const sentences = content
14
- .split(/[.!?]+/)
15
- .map((s) => s.trim())
16
- .filter((s) => s.length > 10 && !s.startsWith("#") && !s.startsWith("---"));
17
- const scoredSentences = [];
18
- for (const sentence of sentences) {
19
- let score = 0;
20
- const sentenceLower = sentence.toLowerCase();
21
- for (const term of queryTerms) {
22
- if (sentenceLower.includes(term)) {
23
- // Count occurrences
24
- const matches = sentenceLower.split(term).length - 1;
25
- score += matches * 2;
26
- }
27
- }
28
- if (score > 0) {
29
- scoredSentences.push({ text: sentence, score });
30
- }
31
- }
32
- // Sort by score and take top N
33
- return scoredSentences
34
- .sort((a, b) => b.score - a.score)
35
- .slice(0, maxSentences)
36
- .map((s) => s.text);
37
- }
38
- /**
39
- * Extract key concepts from page content (from H3 headers, bold text)
40
- */
41
- function extractKeyConcepts(content) {
42
- const concepts = new Set();
43
- // Extract from H3 headers
44
- const h3Matches = content.matchAll(/^###\s+(.+?)$/gm);
45
- for (const match of h3Matches) {
46
- const concept = match[1].trim();
47
- if (concept && concept.length < 80) {
48
- concepts.add(concept);
49
- }
50
- }
51
- // Extract from bold text (but not arrays/JSON)
52
- const boldMatches = content.matchAll(/\*\*([^*]+)\*\*/g);
53
- for (const match of boldMatches) {
54
- const text = match[1].trim();
55
- if (text.length > 3 &&
56
- text.length < 60 &&
57
- !text.includes("[") &&
58
- !text.includes("{") &&
59
- !text.includes('"')) {
60
- concepts.add(text);
61
- }
62
- }
63
- return Array.from(concepts).slice(0, 5);
64
- }
65
- /**
66
- * Build a synthesis answer from multiple source pages
67
- */
68
- function buildSynthesis(query, sourcePages, queryTerms) {
69
- if (!sourcePages.length) {
70
- return {
71
- answer: `No information found related to: ${query}`,
72
- concepts: [],
73
- };
74
- }
75
- const allConcepts = new Set();
76
- const sections = [];
77
- // Add introduction
78
- sections.push(`## Synthesis: ${query}\n`);
79
- sections.push(`Based on ${sourcePages.length} source page(s):\n`);
80
- // Add content from each source
81
- for (const page of sourcePages) {
82
- sections.push(`### ${page.title}`);
83
- sections.push(`*Category: ${page.category} | Relevance: ${Math.round(page.relevance * 100)}%*\n`);
84
- // Extract relevant sentences
85
- const relevantSentences = extractRelevantSentences(page.content, queryTerms, 2);
86
- if (relevantSentences.length > 0) {
87
- sections.push(relevantSentences.map((s) => `- ${s.trim()}`).join("\n"));
88
- }
89
- else {
90
- // Fallback: use first paragraph
91
- const firstPara = page.content
92
- .split("\n")
93
- .filter((l) => l.trim() && !l.startsWith("#") && !l.startsWith("---"))
94
- .slice(0, 1);
95
- sections.push(firstPara.join("\n"));
96
- }
97
- // Collect concepts
98
- const pageConcepts = extractKeyConcepts(page.content);
99
- pageConcepts.forEach((c) => allConcepts.add(c));
100
- sections.push("");
101
- }
102
- // Add summary
103
- sections.push("\n## Key Concepts Found");
104
- Array.from(allConcepts).forEach((c) => {
105
- sections.push(`- ${c}`);
106
- });
107
- sections.push("\n## How to Extend This\n");
108
- sections.push(`This synthesis was generated from ${sourcePages.length} page(s) containing the key terms: `);
109
- sections.push(queryTerms.join(", "));
110
- sections.push("\n\nAdd more source pages to deepen this synthesis.");
111
- return {
112
- answer: sections.join("\n"),
113
- concepts: Array.from(allConcepts),
114
- };
115
- }
116
- async function synthesizeAnswer(input) {
117
- try {
118
- const projectPath = node_path_1.default.resolve(input.project_path);
119
- const docuDir = node_path_1.default.join(projectPath, ".docuflow");
120
- const wikiDir = node_path_1.default.join(docuDir, "wiki");
121
- // Load each source page
122
- const sourcePages = [];
123
- for (const pageId of input.source_page_ids) {
124
- // Try to find the page (scan all category directories)
125
- let found = false;
126
- for (const categoryDir of ["entities", "concepts", "timelines", "syntheses"]) {
127
- const filePath = node_path_1.default.join(wikiDir, categoryDir, `${pageId}.md`);
128
- try {
129
- const read = await (0, filesystem_1.safeReadFile)(filePath);
130
- if (!read.error && !read.binary && read.content) {
131
- const titleMatch = read.content.match(/^#\s+(.+?)$/m);
132
- const title = titleMatch ? titleMatch[1].trim() : pageId;
133
- const category = categoryDir.replace("s", "");
134
- sourcePages.push({
135
- page_id: pageId,
136
- title,
137
- category,
138
- content: read.content,
139
- relevance: 1.0 - (sourcePages.length * 0.1), // Slight decay for order
140
- });
141
- found = true;
142
- break;
143
- }
144
- }
145
- catch (e) {
146
- // Try next category
147
- }
148
- }
149
- if (!found && sourcePages.length === 0) {
150
- // At least one page should be found
151
- return {
152
- query: input.query,
153
- answer: `Could not find source page: ${pageId}`,
154
- source_pages: [],
155
- confidence: 0,
156
- key_concepts: [],
157
- error: `Page not found: ${pageId}`,
158
- };
159
- }
160
- }
161
- // Build query terms
162
- const queryTerms = input.query.toLowerCase().split(/\s+/).filter((t) => t.length > 2);
163
- // Generate synthesis
164
- const { answer, concepts } = buildSynthesis(input.query, sourcePages, queryTerms);
165
- // Calculate confidence based on number and relevance of sources
166
- const confidence = Math.min(1.0, Math.max(0.3, sourcePages.length * 0.25));
167
- return {
168
- query: input.query,
169
- answer,
170
- source_pages: sourcePages.map((p) => ({
171
- page_id: p.page_id,
172
- title: p.title,
173
- category: p.category,
174
- })),
175
- confidence,
176
- key_concepts: concepts,
177
- };
178
- }
179
- catch (e) {
180
- return {
181
- query: input.query,
182
- answer: `Error synthesizing answer: ${e?.message ?? String(e)}`,
183
- source_pages: [],
184
- confidence: 0,
185
- key_concepts: [],
186
- error: e?.message ?? String(e),
187
- };
188
- }
189
- }