@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.
- package/README.md +24 -72
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -328
- package/package.json +5 -7
- package/dist/category-dir.js +0 -12
- package/dist/extractor-rules.js +0 -166
- package/dist/extractor-stoplist.js +0 -89
- package/dist/extractor.js +0 -171
- package/dist/filesystem.js +0 -132
- package/dist/language-map.js +0 -58
- package/dist/tools/answer-synthesis.js +0 -189
- package/dist/tools/build-graph.js +0 -111
- package/dist/tools/generate-dependency-graph.js +0 -162
- package/dist/tools/get-schema-guidance.js +0 -213
- package/dist/tools/ingest-source.js +0 -272
- package/dist/tools/lint-wiki.js +0 -342
- package/dist/tools/list-modules.js +0 -50
- package/dist/tools/list-wiki.js +0 -198
- package/dist/tools/preview-generation.js +0 -228
- package/dist/tools/query-wiki.js +0 -67
- package/dist/tools/read-module.js +0 -53
- package/dist/tools/read-specs.js +0 -39
- package/dist/tools/save-answer-as-page.js +0 -91
- package/dist/tools/update-index.js +0 -157
- package/dist/tools/wiki-search.js +0 -157
- package/dist/tools/write-spec.js +0 -55
- package/dist/types.js +0 -2
|
@@ -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
|
-
}
|
package/dist/filesystem.js
DELETED
|
@@ -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
|
-
}
|
package/dist/language-map.js
DELETED
|
@@ -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
|
-
}
|