@polycode-projects/seonix 0.7.3 → 0.9.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 -114
- package/bin/cli.mjs +12 -10
- package/package.json +3 -4
- package/src/ask-browser-entry.mjs +43 -0
- package/src/ask-browser.bundle.js +3040 -0
- package/src/browser.mjs +1 -0
- package/src/chat-shim.mjs +37 -0
- package/src/codegraph.mjs +30 -17
- package/src/extract.mjs +33 -10
- package/src/interfaces.mjs +171 -0
- package/src/jsts_tsc.mjs +17 -1
- package/src/paths.mjs +31 -0
- package/src/prose.mjs +3 -3
- package/src/schema-docs.mjs +1 -1
- package/src/server.mjs +62 -8
- package/src/sessions.mjs +3 -3
- package/src/source.mjs +16 -3
- package/src/summary.mjs +7 -3
- package/src/tmct-provider.mjs +37 -0
- package/src/toml-config.mjs +13 -0
- package/src/uuid.mjs +1 -1
- package/src/viz.mjs +21 -86
- package/src/ask-nlp.mjs +0 -73
- package/src/ask-vocab.mjs +0 -687
- package/src/ask.mjs +0 -2419
- package/src/chat.mjs +0 -850
- package/src/nlp-bundle.mjs +0 -120
- package/src/prose-nlp.mjs +0 -52
package/src/ask-vocab.mjs
DELETED
|
@@ -1,687 +0,0 @@
|
|
|
1
|
-
// ask-vocab.mjs — the single committed vocabulary `ask.mjs`'s grammar, rephrase
|
|
2
|
-
// hint, and renderer noun forms all derive from (§3 of PLAN_MECHANICAL_CHAT.md).
|
|
3
|
-
// A shipped, hand-curated resource — the same "closed is deliberate" ethos as
|
|
4
|
-
// this repo's other closed vocabularies (SEON/mgx predicates, `.seonixignore`'s
|
|
5
|
-
// gitignore-subset grammar): an open/unbounded phrase list is unvalidatable and
|
|
6
|
-
// eventually produces a false-positive match against an unrelated code
|
|
7
|
-
// identifier, so each relation carries a curated (not exhaustive) set of real
|
|
8
|
-
// phrasings a developer would type, not a general-English thesaurus dump.
|
|
9
|
-
//
|
|
10
|
-
// Modeled on marginalia's app/lib/vocab.mjs pattern (a single source of truth
|
|
11
|
-
// with a `verbs: [...]` trigger-phrase array per token) — minus the RDF/OWL
|
|
12
|
-
// external-alignment machinery, which doesn't apply here: seonix's vocabulary
|
|
13
|
-
// is code-relationship-specific (imports/calls/inherits/…), not a general
|
|
14
|
-
// knowledge-graph ontology. No NLP library, no lemmatiser — plain phrase lists
|
|
15
|
-
// feeding the same fixed-precedence regex grammar `ask.mjs` already used, so
|
|
16
|
-
// broadening coverage never risks the "closed, deterministic, zero model
|
|
17
|
-
// calls" contract this repo holds at every layer (extraction through query).
|
|
18
|
-
|
|
19
|
-
/** relation token -> { comment, verbs[] }. Every phrase in `verbs` must be
|
|
20
|
-
* something a developer would plausibly type asking about THIS relation in
|
|
21
|
-
* THIS codebase's terms — not a synonym so generic it risks matching an
|
|
22
|
-
* unrelated question (see the file-level comment; judgment calls on omitted
|
|
23
|
-
* phrases are logged inline below, not silently dropped).
|
|
24
|
-
*
|
|
25
|
-
* Register spread (2026-07-02, ELIZA/PARRY-style breadth, PLAN_MECHANICAL_CHAT.md
|
|
26
|
-
* §3.5): each relation's `verbs` list deliberately spans formal, neutral, and
|
|
27
|
-
* casual/colloquial phrasings — not just formal synonyms — because the value of
|
|
28
|
-
* a keyword-spotting matcher is SURFACE-FORM tolerance for the same underlying
|
|
29
|
-
* intent, not narrow correctness. Registers are grouped with an inline comment
|
|
30
|
-
* per relation rather than a per-phrase tag (kept flat, matching marginalia's
|
|
31
|
-
* `verbs: [...]` shape) since ask.mjs only needs phrase -> kind, never the
|
|
32
|
-
* register itself. A misparsed casual phrase costs nothing beyond an honest
|
|
33
|
-
* object-miss (resolveObject never guesses), so breadth here is genuinely low-risk. */
|
|
34
|
-
export const RELATIONS = {
|
|
35
|
-
imports: {
|
|
36
|
-
comment: "Module -> Module: subject's import graph references object (usesComplexType).",
|
|
37
|
-
verbs: [
|
|
38
|
-
// formal/neutral ("uses"/"use" moved to the `uses` union family, 2026-07-02 —
|
|
39
|
-
// "uses code from" stays here: its phrasing is specifically import-flavored)
|
|
40
|
-
"couples to", "couple to", "depends on", "imports", "import",
|
|
41
|
-
"relies on", "rely on", "requires", "require", "references", "reference",
|
|
42
|
-
"pulls in", "pull in", "built on", "builds on", "build on", "uses code from",
|
|
43
|
-
// casual/colloquial
|
|
44
|
-
"grabs", "grab", "pulls from", "pull from", "leans on", "lean on",
|
|
45
|
-
"is wired to", "are wired to", "is hooked up to", "are hooked up to",
|
|
46
|
-
// gerund (g-drop normalization turns dialectal "importin'" into this — §3.5)
|
|
47
|
-
"importing",
|
|
48
|
-
],
|
|
49
|
-
},
|
|
50
|
-
// "uses" is a QUERY-side union family, not a stored predicate (2026-07-02 query
|
|
51
|
-
// families): "what uses X" honestly means BOTH the import graph and the call
|
|
52
|
-
// graph, so ask.mjs traverses it as imports + calls + callsSymbol together
|
|
53
|
-
// (KIND_UNIONS there). The verbs moved here FROM imports — "which modules use X"
|
|
54
|
-
// still answers with the importing modules (the asked Module grain filters the
|
|
55
|
-
// union down to module-grain subjects), and "what uses <function>" now also
|
|
56
|
-
// reaches the symbol-grain callers instead of silently ignoring them.
|
|
57
|
-
uses: {
|
|
58
|
-
comment: "query-side union: imports (Module->Module) + calls (Module->Module) + callsSymbol (fn->fn).",
|
|
59
|
-
verbs: [
|
|
60
|
-
"uses", "use", "used by", "makes use of", "make use of",
|
|
61
|
-
// gerund (g-drop normalization — §3.5)
|
|
62
|
-
"using",
|
|
63
|
-
],
|
|
64
|
-
},
|
|
65
|
-
calls: {
|
|
66
|
-
comment: "Function/Method -> Function/Class (symbol-grain) or Module -> Module (coarse): subject invokes object.",
|
|
67
|
-
verbs: [
|
|
68
|
-
// formal
|
|
69
|
-
"invokes", "invoke",
|
|
70
|
-
// neutral
|
|
71
|
-
"calls", "call", "runs", "run", "executes", "execute",
|
|
72
|
-
// casual/colloquial
|
|
73
|
-
"hits", "hit", "triggers", "trigger", "fires", "fire", "kicks off", "kick off",
|
|
74
|
-
// gerund (g-drop normalization turns dialectal "callin'" into this — §3.5)
|
|
75
|
-
"calling",
|
|
76
|
-
],
|
|
77
|
-
},
|
|
78
|
-
defines: {
|
|
79
|
-
comment: "Module -> top-level Function/Class/Method/Attribute: subject declares object.",
|
|
80
|
-
verbs: [
|
|
81
|
-
"defines", "define", "declares", "declare",
|
|
82
|
-
"has", "have", "holds", "hold",
|
|
83
|
-
// gerund (g-drop normalization — §3.5)
|
|
84
|
-
"defining",
|
|
85
|
-
],
|
|
86
|
-
},
|
|
87
|
-
contains: {
|
|
88
|
-
comment: "Class -> Method/Attribute: subject's membership includes object.",
|
|
89
|
-
verbs: [
|
|
90
|
-
"contains", "contain", "lives in", "live in", "is defined in", "are defined in",
|
|
91
|
-
"is part of", "are part of", "sits in", "sit in", "sits inside", "sit inside",
|
|
92
|
-
// gerund (g-drop normalization — §3.5)
|
|
93
|
-
"containing",
|
|
94
|
-
],
|
|
95
|
-
},
|
|
96
|
-
tests: {
|
|
97
|
-
comment: "Module -> Module: subject is a test module importing/covering object.",
|
|
98
|
-
verbs: [
|
|
99
|
-
"tests", "test", "covers", "cover", "verifies", "verify", "exercises", "exercise",
|
|
100
|
-
"checks", "check", "makes sure of", "make sure of",
|
|
101
|
-
// gerund (g-drop normalization — §3.5)
|
|
102
|
-
"testing",
|
|
103
|
-
],
|
|
104
|
-
},
|
|
105
|
-
inherits: {
|
|
106
|
-
comment: "Class -> Class: subject's declared base resolves to object (subclassOf).",
|
|
107
|
-
verbs: [
|
|
108
|
-
"inherits from", "inherit from", "extends", "extend", "subclasses", "subclass",
|
|
109
|
-
"derives from", "derive from", "is a subclass of", "are a subclass of",
|
|
110
|
-
"is a kind of", "are a kind of", "is built off", "are built off",
|
|
111
|
-
"is built on top of", "are built on top of",
|
|
112
|
-
// gerund (g-drop normalization — §3.5, and the compositional grammar's
|
|
113
|
-
// gerund-led boolean gate: "classes inheriting from Base but not tested").
|
|
114
|
-
// Both the two-word "inheriting from" (so "from" is consumed into the verb
|
|
115
|
-
// phrase, not the object term) and the bare "inheriting" (the single token
|
|
116
|
-
// the gerund-lead check reads) are listed; longest-match-first prefers the
|
|
117
|
-
// two-word form when "from" follows.
|
|
118
|
-
"extending", "inheriting from", "inheriting", "subclassing", "extends from",
|
|
119
|
-
],
|
|
120
|
-
},
|
|
121
|
-
touches: {
|
|
122
|
-
comment: "Commit -> Module (coarse) or Commit -> symbol (fine, touchesSymbol): a commit's changed-line-range intersects object.",
|
|
123
|
-
verbs: [
|
|
124
|
-
"touched", "touches", "changed", "change", "modified", "modifies",
|
|
125
|
-
"was changed in", "were changed in", "was edited in", "were edited in",
|
|
126
|
-
"was modified by", "were modified by", "was tweaked in", "were tweaked in",
|
|
127
|
-
"got changed in", "got edited in",
|
|
128
|
-
// commit-question forms (2026-07-02, viewer commit-chat fix): the same touch
|
|
129
|
-
// relation asked from the commit's side — "which changes touch commit <sha>",
|
|
130
|
-
// "what did commit <sha> touch", "which functions changed in <sha>", "which
|
|
131
|
-
// changes landed in commit <sha>", "what was touched by commit <sha>". Bare
|
|
132
|
-
// "touch" completes the touched/touches pair for the "did … touch" auxiliary
|
|
133
|
-
// form; the "by"/"in" phrases are the passive/locative counterparts of forms
|
|
134
|
-
// already above (curated per register spread, not a thesaurus dump).
|
|
135
|
-
"touch", "touched by", "modified by", "changed by", "changed in",
|
|
136
|
-
"landed in", "land in",
|
|
137
|
-
// contents-of-a-commit forms (2026-07-02, operator screenshot: "what was in
|
|
138
|
-
// commit <sha>" missed on the live site). "was in"/"went into" only read as
|
|
139
|
-
// touch questions when the object is a commit — the sha-shaped object keeps
|
|
140
|
-
// them from firing on structural questions ("is X in the graph" has no verb
|
|
141
|
-
// match anyway). Judgment call: "is in" omitted — too generic without the
|
|
142
|
-
// past-tense anchor and risks matching containment phrasings.
|
|
143
|
-
"was in", "were in", "went into", "included in",
|
|
144
|
-
// when-question forms (2026-07-02 query families): "when was X last
|
|
145
|
-
// updated/edited" — bare past participles that only read naturally in the
|
|
146
|
-
// temporal shape; the when template routes them, but they are ordinary
|
|
147
|
-
// touches verbs so "which modules were updated ..." keeps working too.
|
|
148
|
-
"updated", "edited",
|
|
149
|
-
// gerund (g-drop normalization — §3.5)
|
|
150
|
-
"touching",
|
|
151
|
-
],
|
|
152
|
-
},
|
|
153
|
-
cochange: {
|
|
154
|
-
comment: "Module -> Module: subject and object are frequently committed together (changeCoupledWith).",
|
|
155
|
-
verbs: [
|
|
156
|
-
"changed with", "co-changes with", "co-change with", "changes alongside",
|
|
157
|
-
"change alongside", "shares commits with", "share commits with",
|
|
158
|
-
"tends to change together with", "tend to change together with",
|
|
159
|
-
"moves together with", "move together with",
|
|
160
|
-
],
|
|
161
|
-
},
|
|
162
|
-
reexports: {
|
|
163
|
-
comment: "Module -> exported symbol: subject's public API surface (__all__/export list).",
|
|
164
|
-
verbs: [
|
|
165
|
-
"exports", "export", "re-exports", "re-export", "passes through", "pass through",
|
|
166
|
-
// API-surface phrasing (2026-07-02 query families): "what does <module>
|
|
167
|
-
// expose". Bare "exposed" is NOT listed — the lemma tier maps it here when
|
|
168
|
-
// an adapter is present, and "how does the API get exposed" has no
|
|
169
|
-
// traversal either way (pinned as an honest miss in the tests).
|
|
170
|
-
"exposes", "expose",
|
|
171
|
-
// gerund (g-drop normalization — §3.5)
|
|
172
|
-
"exporting",
|
|
173
|
-
],
|
|
174
|
-
},
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
// ---- where/when/mentions markers (2026-07-02 query families) — the location and
|
|
178
|
-
// prose-mention questions carry NO relation verb ("where is X defined", "where is
|
|
179
|
-
// X mentioned"), so ask.mjs routes them by these marker words instead of
|
|
180
|
-
// VERB_TO_KIND. Closed lists, same curation discipline as everything above. ----
|
|
181
|
-
|
|
182
|
-
/** Definition-location markers: "where is X <marker>" (or bare "where is X"). */
|
|
183
|
-
export const WHERE_MARKERS = Object.freeze(["defined", "declared", "located", "implemented"]);
|
|
184
|
-
|
|
185
|
-
/** Prose-mention markers: "where is X <marker>" -> the prose/mentions surface. */
|
|
186
|
-
export const MENTION_MARKERS = Object.freeze(["mentioned", "referenced"]);
|
|
187
|
-
|
|
188
|
-
/** relation token -> flat verb-phrase list, the shape ask.mjs's VERB_TO_KIND
|
|
189
|
-
* table needs (phrase -> kind), derived once from RELATIONS. */
|
|
190
|
-
export const VERB_TO_KIND = Object.freeze(
|
|
191
|
-
Object.fromEntries(
|
|
192
|
-
Object.entries(RELATIONS).flatMap(([kind, { verbs }]) => verbs.map((v) => [v, kind])),
|
|
193
|
-
),
|
|
194
|
-
);
|
|
195
|
-
|
|
196
|
-
export const ENTITY_TO_TYPE = Object.freeze({
|
|
197
|
-
function: "Function", functions: "Function",
|
|
198
|
-
method: "Method", methods: "Method",
|
|
199
|
-
class: "Class", classes: "Class",
|
|
200
|
-
module: "Module", modules: "Module", file: "Module", files: "Module",
|
|
201
|
-
attribute: "Attribute", attributes: "Attribute", field: "Attribute", fields: "Attribute",
|
|
202
|
-
variable: "GlobalVariable", variables: "GlobalVariable", global: "GlobalVariable", globals: "GlobalVariable",
|
|
203
|
-
// "changes" in a touch question ("which changes touch commit <sha>") means the
|
|
204
|
-
// code entities on the other end of the touch edges, at WHATEVER grain the graph
|
|
205
|
-
// recorded — module (touches) and symbol (touchesSymbol) together when the commit
|
|
206
|
-
// is the given side, and the touching commits themselves when a module/symbol is
|
|
207
|
-
// the given side. Mapped to the pseudo-type "Change" (not a node class): ask.mjs's
|
|
208
|
-
// traverse() reads it as a wildcard over the touch traversal's results rather than
|
|
209
|
-
// aliasing it to ONE real class and silently dropping the other grain of the
|
|
210
|
-
// answer. Listed BEFORE commit/commits: findPhrase (ask.mjs) takes the first
|
|
211
|
-
// same-length phrase in table order, so in "which changes touch commit <sha>" the
|
|
212
|
-
// entity slot must consume "changes" and leave "commit <sha>" intact as the
|
|
213
|
-
// object term.
|
|
214
|
-
change: "Change", changes: "Change",
|
|
215
|
-
commit: "Commit", commits: "Commit",
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
export const MODIFIER_TO_KIND = Object.freeze({
|
|
219
|
-
explicitly: "direct", directly: "direct",
|
|
220
|
-
transitively: "transitive", indirectly: "transitive",
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
// ---- §3.5 normalization — contractions/informal spellings that would otherwise
|
|
224
|
-
// block a match, expanded BEFORE parsing (BOTH the anchored-template strategy
|
|
225
|
-
// and the independent keyword-spotting strategy see the same normalized text —
|
|
226
|
-
// this table is not owned by either). Small and code-question-scoped, not a
|
|
227
|
-
// general slang dictionary — every entry here exists because it appears in an
|
|
228
|
-
// actual worked example this file's matcher must handle. ----
|
|
229
|
-
export const CONTRACTIONS = Object.freeze({
|
|
230
|
-
"ain't": "is not", "aint": "is not",
|
|
231
|
-
"isn't": "is not", "isnt": "is not",
|
|
232
|
-
"aren't": "are not", "arent": "are not",
|
|
233
|
-
"doesn't": "does not", "doesnt": "does not",
|
|
234
|
-
"don't": "do not", "dont": "do not",
|
|
235
|
-
"didn't": "did not", "didnt": "did not",
|
|
236
|
-
"there's": "there is", "theres": "there is",
|
|
237
|
-
"what's": "what is", "whats": "what is",
|
|
238
|
-
"who's": "who is", "whos": "who is",
|
|
239
|
-
"gonna": "going to",
|
|
240
|
-
"wanna": "want to",
|
|
241
|
-
"gotta": "got to",
|
|
242
|
-
"yer": "your", "ur": "your",
|
|
243
|
-
"gimme": "give me",
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
// ---- misspellings and wrong words (2026-07-02, two-level fuzzy work) — these are
|
|
247
|
-
// CORRECTIONS, not synonyms: the asker typed a broken or incorrect surface form of
|
|
248
|
-
// a word this grammar already owns, and we restore the canonical form BEFORE
|
|
249
|
-
// parsing (normalizeQuery applies both tables like CONTRACTIONS: word-boundary,
|
|
250
|
-
// longest key first, case-insensitive). Synonyms belong in RELATIONS/ENTITY_TO_TYPE;
|
|
251
|
-
// these tables exist so a typo'd or misused word maps to canonical language
|
|
252
|
-
// deterministically, ahead of (and more precisely than) ask.mjs's bounded
|
|
253
|
-
// edit-distance fallback. ask.mjs's correction regex refuses to rewrite a word
|
|
254
|
-
// glued to a dotted extension ("revision.mjs" stays a module name), since
|
|
255
|
-
// WRONG_WORDS entries are real English words that plausibly name modules; a
|
|
256
|
-
// bare standalone token that happens to be a real identifier remains the
|
|
257
|
-
// accepted residual exposure, same as CONTRACTIONS. ----
|
|
258
|
-
|
|
259
|
-
/** Curated common typos of THIS vocabulary's own keywords — entity nouns, relation
|
|
260
|
-
* verbs, and the grammar's anchor words (which/what/does/the): a typo'd anchor
|
|
261
|
-
* kills the anchored templates outright, so anchors earn entries too. Values are
|
|
262
|
-
* always the canonical word. Judgment calls logged: "calss" maps to "class" (the
|
|
263
|
-
* doubled-s slip of "class"), NOT "calls", though both are edit-distance 1 — the
|
|
264
|
-
* exact tie the generic fuzzy tier must refuse to break; a curated table is where
|
|
265
|
-
* that call is made deliberately. "dose" is a real English word, but at a word
|
|
266
|
-
* boundary in this closed question grammar ("dose X import Y") the intent is
|
|
267
|
-
* unambiguous. */
|
|
268
|
-
export const MISSPELLINGS = Object.freeze({
|
|
269
|
-
// entity nouns
|
|
270
|
-
"funtion": "function", "funtions": "functions",
|
|
271
|
-
"fucntion": "function", "fucntions": "functions",
|
|
272
|
-
"functoin": "function", "functoins": "functions",
|
|
273
|
-
"calss": "class", "calsses": "classes", "classs": "class", "clases": "classes",
|
|
274
|
-
"modul": "module", "moduls": "modules",
|
|
275
|
-
"moduel": "module", "moduels": "modules",
|
|
276
|
-
"moudle": "module", "moudles": "modules",
|
|
277
|
-
"methdo": "method", "methdos": "methods",
|
|
278
|
-
"mehtod": "method", "mehtods": "methods",
|
|
279
|
-
"comit": "commit", "comits": "commits",
|
|
280
|
-
"commmit": "commit", "commmits": "commits",
|
|
281
|
-
"varaible": "variable", "varaibles": "variables",
|
|
282
|
-
"varibale": "variable", "varibales": "variables",
|
|
283
|
-
"atribute": "attribute", "atributes": "attributes",
|
|
284
|
-
// relation verbs
|
|
285
|
-
"improt": "import", "improts": "imports",
|
|
286
|
-
"imoprt": "import", "imoprts": "imports",
|
|
287
|
-
"inherts": "inherits", "inheirts": "inherits",
|
|
288
|
-
"extands": "extends", "extneds": "extends",
|
|
289
|
-
"depnds": "depends",
|
|
290
|
-
"touchs": "touches", "tuoches": "touches", "touhced": "touched",
|
|
291
|
-
"chagned": "changed", "chnaged": "changed",
|
|
292
|
-
"chagnes": "changes", "chnages": "changes",
|
|
293
|
-
"calles": "calls",
|
|
294
|
-
"exprot": "export", "exprots": "exports",
|
|
295
|
-
"tets": "tests",
|
|
296
|
-
// grammar anchor words
|
|
297
|
-
"whcih": "which", "wich": "which", "whihc": "which",
|
|
298
|
-
"waht": "what",
|
|
299
|
-
"dose": "does", "doess": "does",
|
|
300
|
-
"teh": "the",
|
|
301
|
-
// aggregate/list TRIGGER words (2026-07-02, trigger-typo work) — a typo of a count
|
|
302
|
-
// or list trigger used to be DROPPED as unmatched by the relaxation cascade, losing
|
|
303
|
-
// the aggregate/list INTENT entirely ("how manyn classes" → the count was lost);
|
|
304
|
-
// curated here so the intended trigger is restored BEFORE parsing (the general
|
|
305
|
-
// bounded fuzzy path in ask.mjs's cascade is the backstop for uncurated typos).
|
|
306
|
-
"manyn": "many", "mnay": "many", "amny": "many", "mnany": "many",
|
|
307
|
-
"coutn": "count", "conut": "count", "cuont": "count", "ocunt": "count",
|
|
308
|
-
"numer": "number", "nubmer": "number", "numbr": "number", "nmuber": "number",
|
|
309
|
-
"lst": "list", "lsit": "list", "ilst": "list",
|
|
310
|
-
"shwo": "show", "hsow": "show",
|
|
311
|
-
"dispaly": "display", "dsiplay": "display",
|
|
312
|
-
"funtcions": "functions", "funciton": "function", "funcitons": "functions",
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
/** Words used INCORRECTLY but with clear intent, mapped to the canonical schema
|
|
316
|
-
* term — used like synonyms by the asker, but they are corrections of usage, not
|
|
317
|
-
* alternative names (which is why they live here and not in ENTITY_TO_TYPE).
|
|
318
|
-
* Only mapped where intent is unambiguous in a code-graph question; words
|
|
319
|
-
* deliberately NOT mapped are logged in the omitted-on-purpose block at the end
|
|
320
|
-
* of this file. */
|
|
321
|
-
export const WRONG_WORDS = Object.freeze({
|
|
322
|
-
// neither a folder nor a directory grain exists in this graph — in "which
|
|
323
|
-
// folders import X" the only honest referent is the module/file grain.
|
|
324
|
-
"folder": "module", "folders": "modules",
|
|
325
|
-
"directory": "module", "directories": "modules",
|
|
326
|
-
// unambiguous abbreviation of an entity noun this grammar owns
|
|
327
|
-
"func": "function", "funcs": "functions",
|
|
328
|
-
// VCS terms whose canonical schema class here is Commit
|
|
329
|
-
"changeset": "commit", "changesets": "commits",
|
|
330
|
-
"revision": "commit", "revisions": "commits",
|
|
331
|
-
// code-graph "property" is the Attribute grain in this schema
|
|
332
|
-
"property": "attribute", "properties": "attributes",
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
/** Trailing g-drop ("callin'", "hittin'") — a plain suffix restore, not a
|
|
336
|
-
* lemmatiser: -in' -> -ing, applied per-word during normalization. The
|
|
337
|
-
* apostrophe is REQUIRED (not optional): bare "-in" endings with no
|
|
338
|
-
* apostrophe are real English words far more often than dropped g's
|
|
339
|
-
* ("cabin", "robin", "chin", "twin") — restoring those would be a false
|
|
340
|
-
* positive the anchored templates never had to worry about. No trailing
|
|
341
|
-
* `\b` after the apostrophe: `'` is a non-word character, so a `\b` there
|
|
342
|
-
* can never match the (non-word) whitespace/end-of-string that follows —
|
|
343
|
-
* the apostrophe itself already delimits the word, a second boundary check
|
|
344
|
-
* after it is redundant and unmatchable. */
|
|
345
|
-
export const G_DROP = /\b([a-z]{3,})in'/gi;
|
|
346
|
-
|
|
347
|
-
/** Words stripped during normalization/keyword-spotting once they carry no
|
|
348
|
-
* grammatical weight for this grammar — greetings, politeness, hedges, and
|
|
349
|
-
* the discourse fillers a spoken-style question picks up. Never strips a
|
|
350
|
-
* relation verb, entity noun, or modifier (those are checked first). */
|
|
351
|
-
export const FILLER_WORDS = Object.freeze([
|
|
352
|
-
"um", "uh", "erm", "so", "like", "yo", "hey", "bru", "bro", "fam", "mate",
|
|
353
|
-
"please", "could you", "can you", "would you", "tell me", "i wonder",
|
|
354
|
-
"just wondering", "quickly", "real quick", "kinda", "sorta",
|
|
355
|
-
]);
|
|
356
|
-
|
|
357
|
-
/** Deictic/pronoun terms that refer to a context entity rather than naming one
|
|
358
|
-
* directly — resolved against an optional `contextId` (ask.mjs §keyword-
|
|
359
|
-
* spotting; wired from the graph viewer's currently-selected node, when the
|
|
360
|
-
* chat panel is asking "about" whatever the user last clicked). With no
|
|
361
|
-
* context available (the bare CLI/MCP surface), these produce an honest
|
|
362
|
-
* "which node does 'this' refer to?" miss — never a guess. */
|
|
363
|
-
export const CONTEXT_PRONOUNS = Object.freeze(["this", "it", "that", "here", "this one", "that one"]);
|
|
364
|
-
|
|
365
|
-
// ---- §3.6 negation frames — a SMALL, pattern-based set of recognized
|
|
366
|
-
// double-negative / negative-rhetorical constructions, normalized to the
|
|
367
|
-
// affirmative form of the SAME question (not a general negation-scope parser
|
|
368
|
-
// — ELIZA/PARRY's own scope discipline: a handful of recognized frames, not
|
|
369
|
-
// an attempt at full logical negation handling). Each frame is tried in
|
|
370
|
-
// order; the first match rewrites the whole string and normalization stops
|
|
371
|
-
// (a second negation frame firing on an already-rewritten string would be a
|
|
372
|
-
// design smell, not a feature). ----
|
|
373
|
-
export const NEGATION_FRAMES = Object.freeze([
|
|
374
|
-
// "there ain't nothin' calling it" / "there isn't nothing that calls it"
|
|
375
|
-
// -> "what calls it"
|
|
376
|
-
{ re: /\bthere\s+is\s+not\s+(?:anything|nothing)\s+(?:that\s+)?(\S.*)$/i, to: (m) => `what ${m[1]}` },
|
|
377
|
-
// "there's no module that imports auth" -> "what imports auth"
|
|
378
|
-
{ re: /\bthere\s+is\s+no\s+\S+\s+(?:that\s+)?(\S.*)$/i, to: (m) => `what ${m[1]}` },
|
|
379
|
-
// "isn't there anything calling it" -> "what calls it" (question-inverted form)
|
|
380
|
-
{ re: /\bis\s+not\s+there\s+(?:anything|nothing)\s+(?:that\s+)?(\S.*)$/i, to: (m) => `what ${m[1]}` },
|
|
381
|
-
// "nobody/nothing calls it, does it" (tag-question double-negative) -> "what calls it"
|
|
382
|
-
{ re: /\b(?:nobody|nothing|no one)\s+(\S.*?)(?:,?\s+does\s+it\??|,?\s+do\s+they\??)?$/i, to: (m) => `what ${m[1]}` },
|
|
383
|
-
]);
|
|
384
|
-
|
|
385
|
-
// ---- commit-content frames (2026-07-02, operator screenshot: "what was in commit
|
|
386
|
-
// ef74e44e25c8" missed on the live site) — "what was/is in commit <sha>", "what's
|
|
387
|
-
// in <sha>" (the contraction table has already expanded "what's" by the time
|
|
388
|
-
// frames run), "what went into <sha>", "what made it into commit <sha>" all mean
|
|
389
|
-
// the canonical commit-subject question "what did <sha> touch", so they are
|
|
390
|
-
// REWRITTEN to it before either parse strategy runs: the same mechanism and scope
|
|
391
|
-
// discipline as NEGATION_FRAMES (a small closed pattern set, first match wins),
|
|
392
|
-
// which also makes both strategies parse the family for free. The sha-shaped tail
|
|
393
|
-
// is REQUIRED so these frames only ever fire on an actual commit reference: over a
|
|
394
|
-
// non-sha object ("what was in walk.mjs") the frame does not match and the text is
|
|
395
|
-
// left for the ordinary grammar to handle as it already does, rather than being
|
|
396
|
-
// bent into a commit-subject touches query that would then blank. ----
|
|
397
|
-
export const COMMIT_CONTENT_FRAMES = Object.freeze([
|
|
398
|
-
// "what was in commit ef74e44e25c8" / "what is in ef74e44e" / "what's in commit <sha>"
|
|
399
|
-
{ re: /^what\s+(?:is|was|were|are)\s+in\s+((?:commit\s+)?[0-9a-f]{7,40})\??$/i, to: (m) => `what did ${m[1]} touch` },
|
|
400
|
-
// "what went into commit ef74e44e25c8" / casual "what got into <sha>"
|
|
401
|
-
{ re: /^what\s+(?:went|got)\s+into\s+((?:commit\s+)?[0-9a-f]{7,40})\??$/i, to: (m) => `what did ${m[1]} touch` },
|
|
402
|
-
// "what made it into commit ef74e44e25c8"
|
|
403
|
-
{ re: /^what\s+made\s+it\s+into\s+((?:commit\s+)?[0-9a-f]{7,40})\??$/i, to: (m) => `what did ${m[1]} touch` },
|
|
404
|
-
]);
|
|
405
|
-
|
|
406
|
-
// ---- §7 meta-vocabulary — trigger phrases for the "meta" query shape (asking what a
|
|
407
|
-
// graph vocabulary term itself means: "what does cochange mean", "what does mgx:
|
|
408
|
-
// callsSymbol mean"). Deliberately NOT folded into RELATIONS/VERB_TO_KIND: these
|
|
409
|
-
// phrases don't name a graph relation kind for edgesOfKind to traverse, they name
|
|
410
|
-
// "explain this term" intent. Adding them to VERB_TO_KIND would make
|
|
411
|
-
// parseKeywordSpot's decomposition matcher independently derive a *different* shape
|
|
412
|
-
// ("forward", the only shape its before-only-text case produces) for the very same
|
|
413
|
-
// sentence the anchored meta template resolves to shape:"meta" — a spurious strategy
|
|
414
|
-
// DISAGREEMENT (ambiguousParse) on every meta question. So this table is read directly
|
|
415
|
-
// by ask.mjs's own meta template, never merged into the shared verb tables. ----
|
|
416
|
-
export const META_MEANING_VERBS = Object.freeze([
|
|
417
|
-
"mean", "means", "stand for", "stands for", "signify", "signifies",
|
|
418
|
-
"represent", "represents", "refer to", "refers to",
|
|
419
|
-
]);
|
|
420
|
-
|
|
421
|
-
// ---- §compositional grammar vocabulary (PLAN §5.16 P3 — the ask engine's step up
|
|
422
|
-
// from ELIZA keyword-spotting to a real recursive-descent grammar over CLAUSES).
|
|
423
|
-
// ask.mjs's parseComposite reads these tables to recognize the compositional
|
|
424
|
-
// MARKERS — relative clauses, boolean connectives, subject qualifiers, aggregates,
|
|
425
|
-
// superlatives, and anaphora — that compose the SAME closed clause vocabulary
|
|
426
|
-
// (RELATIONS/ENTITY_TO_TYPE above) into multi-hop / set-algebra queries. The
|
|
427
|
-
// grammar COMPOSES the closed vocabulary; it never opens it. Every table here is
|
|
428
|
-
// curated + closed, same discipline as everything above: a marker the tables don't
|
|
429
|
-
// carry is an honest miss, never a guess. ----
|
|
430
|
-
|
|
431
|
-
/** Relative-clause introducers: "<noun> that/which/who <predicate>". Only ever
|
|
432
|
-
* read as a relative pronoun when it sits AFTER a noun and BEFORE a predicate
|
|
433
|
-
* (ask.mjs enforces both) — "that" is also a CONTEXT_PRONOUN ("what calls that"),
|
|
434
|
-
* so position, not mere presence, decides. This gates the nested/relative and
|
|
435
|
-
* same-subject boolean shapes: their absence is exactly what keeps the bare
|
|
436
|
-
* reverse-template query "which classes extends Base and couples to logging" out
|
|
437
|
-
* of the compositional path (it stays the existing two-strategy ambiguous parse). */
|
|
438
|
-
export const RELATIVE_PRONOUNS = Object.freeze(["that", "which", "who"]);
|
|
439
|
-
|
|
440
|
-
/** Placeholder object nouns — the indefinite "something" in "what calls something
|
|
441
|
-
* that imports X": they name NO entity, they stand in for the inner clause's
|
|
442
|
-
* result set. Mapped to entityType null (any grain); a real entity noun in the
|
|
443
|
-
* same slot ("what calls modules that import X") narrows the grain instead. */
|
|
444
|
-
export const PLACEHOLDER_NOUNS = Object.freeze([
|
|
445
|
-
"something", "anything", "everything", "somethings", "things", "thing",
|
|
446
|
-
"entities", "entity", "nodes", "node", "stuff", "code",
|
|
447
|
-
// "symbol(s)" is a grain-agnostic stand-in for any code entity — "exported
|
|
448
|
-
// symbols of X" means whatever X defines, at any grain, filtered by the qualifier.
|
|
449
|
-
"symbol", "symbols",
|
|
450
|
-
]);
|
|
451
|
-
|
|
452
|
-
/** Boolean connectives over same-subject clauses -> a set operation on result ids.
|
|
453
|
-
* "and" = intersection, "or" = union, "but not"/"and not"/"without"/"except" =
|
|
454
|
-
* difference. Multi-word keys are matched longest-first by ask.mjs so "but not"
|
|
455
|
-
* wins over a bare "not". Left-associative in ask.mjs's fold. */
|
|
456
|
-
export const BOOLEAN_CONNECTIVES = Object.freeze({
|
|
457
|
-
"but not": "difference", "and not": "difference", "except": "difference",
|
|
458
|
-
"without": "difference",
|
|
459
|
-
"and": "intersection", "plus": "intersection",
|
|
460
|
-
"or": "union",
|
|
461
|
-
});
|
|
462
|
-
|
|
463
|
-
/** Subject QUALIFIERS (adjectives) -> a post-filter over the result set, read off
|
|
464
|
-
* attributes/edges the graph already carries (codegraph.mjs): `visibility`
|
|
465
|
-
* (private/protected present; public is the default/absent), `isStatic`/
|
|
466
|
-
* `isConstant`/`isAbstract` boolean attrs, the reexports edge set (exported), and
|
|
467
|
-
* the tests edge set (tested/untested). `isAbstract` is never populated by any
|
|
468
|
-
* extractor today (codegraph.mjs says so) — "abstract methods" therefore honestly
|
|
469
|
-
* returns an empty set, not an error, exactly like any other zero-hit answer. An
|
|
470
|
-
* UNKNOWN qualifier is an honest miss naming these supported ones (ask.mjs). */
|
|
471
|
-
export const QUALIFIERS = Object.freeze({
|
|
472
|
-
public: { via: "visibility", value: "public" },
|
|
473
|
-
private: { via: "visibility", value: "private" },
|
|
474
|
-
protected: { via: "visibility", value: "protected" },
|
|
475
|
-
static: { via: "attr", attr: "isStatic" },
|
|
476
|
-
abstract: { via: "attr", attr: "isAbstract" },
|
|
477
|
-
constant: { via: "attr", attr: "isConstant" },
|
|
478
|
-
exported: { via: "exported" },
|
|
479
|
-
"re-exported": { via: "exported" },
|
|
480
|
-
tested: { via: "tested", value: true },
|
|
481
|
-
covered: { via: "tested", value: true },
|
|
482
|
-
untested: { via: "tested", value: false },
|
|
483
|
-
uncovered: { via: "tested", value: false },
|
|
484
|
-
});
|
|
485
|
-
|
|
486
|
-
/** Aggregate/count triggers: "how many <kind> …", "count <kind>s", "number of
|
|
487
|
-
* <kind>". Answered by counting a class of individuals or a clause's result set —
|
|
488
|
-
* no header magic, a straight count over the graph (ask.mjs). Register-spread the
|
|
489
|
-
* same way RELATIONS' verbs are (2026-07-02): the count question has a formal
|
|
490
|
-
* ("how many"/"number of"), a neutral/imperative ("count"/"count up"), and a
|
|
491
|
-
* quantity ("quantity of"/"total number of") register a developer actually types.
|
|
492
|
-
* Judgement calls, kept OUT deliberately: bare "tally"/"sum"/"total" — those are
|
|
493
|
-
* already mapped to "count" by CASCADE_SYNONYMS (ask.mjs's relaxation layer), and a
|
|
494
|
-
* cascade test asserts "tally the classes" reaches the count via that synonym path,
|
|
495
|
-
* so promoting them to direct triggers here would both duplicate the mapping and
|
|
496
|
-
* break that test; and single-word "total"/"sum" would false-match identifier
|
|
497
|
-
* fragments ("total price", "sum of squares") the count intent never meant. */
|
|
498
|
-
export const AGGREGATE_TRIGGERS = Object.freeze([
|
|
499
|
-
// formal ("the number of classes" reaches "number of" once the cascade strips the
|
|
500
|
-
// leading article — keeping the trigger list clear of "the" so it never enters
|
|
501
|
-
// CONTENT_VOCAB and blocks the article's own noise-strip)
|
|
502
|
-
"how many", "how much", "how many of", "number of",
|
|
503
|
-
"total number of", "quantity of",
|
|
504
|
-
// neutral / imperative
|
|
505
|
-
"count", "count up", "count of", "tot up",
|
|
506
|
-
]);
|
|
507
|
-
|
|
508
|
-
/** LIST triggers (2026-07-02, list shape) — the many ways a developer asks to SEE the
|
|
509
|
-
* individuals of a kind ("list functions", "show me the classes", "what are the
|
|
510
|
-
* modules"). Read by ask.mjs's parseList (a sibling of the count node): a trigger
|
|
511
|
-
* followed by an entity kind noun lists that class (capped at OVERFLOW_CAP), a
|
|
512
|
-
* trailing scope/predicate narrows it, and an unknown kind after a clear list trigger
|
|
513
|
-
* is an honest miss naming the kinds. Two registers, wide-but-deliberate (the operator's
|
|
514
|
-
* "err toward inclusion", bounded by the file-header discipline: a phrase earns its
|
|
515
|
-
* place only if it genuinely means "enumerate these" and won't false-match an unrelated
|
|
516
|
-
* identifier — parseList further requires a real entity kind to follow, so a stray
|
|
517
|
-
* "show"/"name" in another question is never seized):
|
|
518
|
-
* · IMPERATIVE — "<verb> [me/us] [the] <kind>". Bare determiners/objects (the/a/all/
|
|
519
|
-
* me/us) after the verb are skipped by parseList's LIST_SKIP, so only the verb stem
|
|
520
|
-
* is listed here (not every "... the"/"... all" inflection).
|
|
521
|
-
* · INTERROGATIVE — "what/which are [the] <kind>"; the bare "what <kind>"/"which
|
|
522
|
-
* <kind>" (+ optional "are there") form is handled directly in parseList, not here.
|
|
523
|
-
* Kept OUT on purpose: "tell me" / "give me" collide only where normalizeQuery already
|
|
524
|
-
* strips them as FILLER_WORDS ("tell me the classes" → "the classes"), so "tell me" is
|
|
525
|
-
* omitted (it never survives to parseList); "gimme" is omitted because CONTRACTIONS
|
|
526
|
-
* rewrites it to "give me" before parseList runs. */
|
|
527
|
-
export const LIST_TRIGGERS = Object.freeze([
|
|
528
|
-
// imperative — "<verb> [me/us] [the] <kind>"
|
|
529
|
-
"list", "show", "show me", "show us", "display", "print", "print out",
|
|
530
|
-
"dump", "enumerate", "name", "give me", "get me", "spit out", "rattle off",
|
|
531
|
-
"run down", "run through", "ls",
|
|
532
|
-
// interrogative — "what/which are [the] <kind>"
|
|
533
|
-
"what are", "which are",
|
|
534
|
-
]);
|
|
535
|
-
|
|
536
|
-
/** Superlative extremes -> ranking direction. "most/greatest/highest/biggest/
|
|
537
|
-
* largest/most-connected" rank descending; "fewest/least/smallest/lowest" rank
|
|
538
|
-
* ascending. Read by ask.mjs's parseSuperlative alongside EDGE_NOUN_TO_METRIC. */
|
|
539
|
-
export const SUPERLATIVE_EXTREMES = Object.freeze({
|
|
540
|
-
most: "most", greatest: "most", highest: "most", biggest: "most",
|
|
541
|
-
largest: "most", "most-connected": "most", "most connected": "most",
|
|
542
|
-
fewest: "fewest", least: "fewest", smallest: "fewest", lowest: "fewest",
|
|
543
|
-
});
|
|
544
|
-
|
|
545
|
-
/** Degree-metric nouns for superlatives ("which module has the most <noun>") ->
|
|
546
|
-
* {kind, dir} over the SAME classified edge groups. dir "out" counts edges where
|
|
547
|
-
* the ranked entity is the subject (its own imports/calls); "in" counts edges
|
|
548
|
-
* where it is the object (its importers/callers/tests). "connections"/"edges"/
|
|
549
|
-
* "connected" is the total (both directions, all structural kinds). A `sibling`
|
|
550
|
-
* fine-grained kind is added to the tally when present (callers include the
|
|
551
|
-
* symbol-grain callsSymbol edges, not just module-coarse calls); a `filter`
|
|
552
|
-
* restricts the counted objects to one class ("methods"). */
|
|
553
|
-
export const EDGE_NOUN_TO_METRIC = Object.freeze({
|
|
554
|
-
imports: { kind: "imports", dir: "out" },
|
|
555
|
-
dependencies: { kind: "imports", dir: "out" },
|
|
556
|
-
importers: { kind: "imports", dir: "in" },
|
|
557
|
-
dependents: { kind: "imports", dir: "in" },
|
|
558
|
-
callers: { kind: "calls", dir: "in", sibling: "callsSymbol" },
|
|
559
|
-
callees: { kind: "calls", dir: "out", sibling: "callsSymbol" },
|
|
560
|
-
calls: { kind: "calls", dir: "out", sibling: "callsSymbol" },
|
|
561
|
-
methods: { kind: "contains", dir: "out", filter: "Method" },
|
|
562
|
-
members: { kind: "contains", dir: "out" },
|
|
563
|
-
tests: { kind: "tests", dir: "in" },
|
|
564
|
-
subclasses: { kind: "inherits", dir: "in" },
|
|
565
|
-
connections: { kind: "*", dir: "both" },
|
|
566
|
-
edges: { kind: "*", dir: "both" },
|
|
567
|
-
connected: { kind: "*", dir: "both" },
|
|
568
|
-
});
|
|
569
|
-
|
|
570
|
-
/** Anaphora triggers over the PREVIOUS result set (ask()'s `prev` id array):
|
|
571
|
-
* "which of those/them/these …", "how many of those …". The pronoun refers to the
|
|
572
|
-
* last answer's ids, not a graph term — with no prev supplied it is an honest miss
|
|
573
|
-
* (ask.mjs), never a guess, exactly like an unresolved context pronoun. */
|
|
574
|
-
export const ANAPHORA_TRIGGERS = Object.freeze(["those", "them", "these"]);
|
|
575
|
-
|
|
576
|
-
/** Membership relations for "<entity> of/in <term>" (qualifier/relative inner
|
|
577
|
-
* clauses like "public methods of Widget", "untested functions in walk.mjs") ->
|
|
578
|
-
* the forward edge kinds whose subject is <term> and whose objects are the
|
|
579
|
-
* members. contains (Class->member) and defines (Module->symbol) are both tried;
|
|
580
|
-
* the asked entity type narrows the result. */
|
|
581
|
-
export const MEMBERSHIP_KINDS = Object.freeze(["contains", "defines"]);
|
|
582
|
-
|
|
583
|
-
// ---- §progressive-relaxation cascade vocabulary (SHRDLU-in-a-code-graph, with a
|
|
584
|
-
// Zork parser's forgiveness) — the three closed, curated tables ask.mjs's relaxParse
|
|
585
|
-
// reads when the DIRECT parse of a query would MISS. The cascade only ever DROPS
|
|
586
|
-
// noise/unmatched words or NORMALISES a near-canonical word to the closed vocabulary;
|
|
587
|
-
// it never invents a term or guesses an entity, and it bottoms out in the same honest
|
|
588
|
-
// rephrase hint. Every entry is hand-curated with inline provenance, same "closed is
|
|
589
|
-
// deliberate" ethos as everything above: a word these tables don't carry is left for
|
|
590
|
-
// the honest miss, never a general-English stoplist that would silently eat a real
|
|
591
|
-
// code term. ----
|
|
592
|
-
|
|
593
|
-
/** Politeness / filler / vocative / presentation-frame tokens the cascade may strip
|
|
594
|
-
* ONE AT A TIME (leftmost first) when a query misses — but only ever a token that is
|
|
595
|
-
* NOT itself a content vocabulary word (a relation verb, entity noun, modifier,
|
|
596
|
-
* qualifier, aggregate/superlative trigger, …) and does NOT resolve to a graph entity
|
|
597
|
-
* (ask.mjs guards both), so a module literally named "show" or "the" is never eaten.
|
|
598
|
-
* This is a SUPERSET of the multi-word politeness FILLER_WORDS strips up-front during
|
|
599
|
-
* normalization: those handle "could you"/"tell me"/"please" before either parse runs;
|
|
600
|
-
* these single tokens catch what a spoken-style question keeps AFTER that pass — the
|
|
601
|
-
* bare vocative ("matey"), the article ("the"/"a"), and the presentation frame words
|
|
602
|
-
* ("show"/"me"/"list") that the compositional grammar already skips as FRAME_WORDS but
|
|
603
|
-
* the keyword-spotting strategy does not, so an un-stripped "show me" otherwise
|
|
604
|
-
* decomposes to a bogus ask{subject:"show me"}. Curated, not a general stoplist:
|
|
605
|
-
* question words (what/which/…), connectives (and/or), and pronouns (this/it/that)
|
|
606
|
-
* are deliberately ABSENT — they carry grammatical weight and must survive. */
|
|
607
|
-
export const CASCADE_NOISE = Object.freeze([
|
|
608
|
-
// articles / vague determiners (kept OUT of content vocab so they're strippable;
|
|
609
|
-
// the aggregate/where parsers already tolerate a stray "the"/"a", so stripping is
|
|
610
|
-
// belt-and-braces, not load-bearing)
|
|
611
|
-
"the", "a", "an", "some",
|
|
612
|
-
// topic lead-in filler — "what about the modules", "how about classes": "about"
|
|
613
|
-
// carries no graph meaning here, so stripping it lets the bare kind noun surface for
|
|
614
|
-
// the cascade's bare-kind-noun terminal rule (ask.mjs). ("what"/"how" are structural
|
|
615
|
-
// question words the drop-pass keeps; only the "about" between them and the kind is
|
|
616
|
-
// noise.) A module literally named "about" is safe-listed by relaxParse's resolvesExact
|
|
617
|
-
// guard, same as every other noise token.
|
|
618
|
-
"about",
|
|
619
|
-
// politeness / hedges (single-token; multi-word "could you"/"please" etc. are
|
|
620
|
-
// FILLER_WORDS, stripped earlier during normalization)
|
|
621
|
-
"please", "pls", "plz", "kindly", "just", "simply", "maybe", "perhaps",
|
|
622
|
-
"thanks", "thank", "ta", "cheers",
|
|
623
|
-
// greetings a question sometimes opens with (chat.mjs owns standalone greetings;
|
|
624
|
-
// here they're only stripped when embedded in an otherwise-real question)
|
|
625
|
-
"hi", "hello", "hey", "yo", "hiya", "howdy", "ok", "okay",
|
|
626
|
-
// vocatives / terms of address (the "matey" of the worked example, and its kin)
|
|
627
|
-
"matey", "mate", "buddy", "pal", "dude", "man", "bro", "bru", "fam",
|
|
628
|
-
"friend", "sir", "maam", "folks", "guys", "everyone", "dear",
|
|
629
|
-
// presentation frames — the keyword-spotting strategy's blind spot: the
|
|
630
|
-
// compositional grammar skips these as FRAME_WORDS, but "show me what imports X"
|
|
631
|
-
// otherwise decomposes (via keyword-spot) to ask{subject:"show me"}. Stripping
|
|
632
|
-
// them on a miss recovers the underlying reverse/forward question. ("count" is NOT
|
|
633
|
-
// here — it is an aggregate trigger; "find"/"search" are here as presentation
|
|
634
|
-
// verbs, not the seonix_search tool, which ask.mjs never dispatches.)
|
|
635
|
-
"show", "tell", "give", "list", "find", "me", "us", "lemme",
|
|
636
|
-
]);
|
|
637
|
-
|
|
638
|
-
/** Near-canonical words the cascade REWRITES to the closed vocabulary once noise and
|
|
639
|
-
* unmatched tokens are gone (SYNONYM-NORMALISE, the cascade's third layer). Kept
|
|
640
|
-
* deliberately TINY and aggregate-flavoured: the relation/entity synonyms a developer
|
|
641
|
-
* actually types already live in RELATIONS/ENTITY_TO_TYPE (and "uses"/"depends on" are
|
|
642
|
-
* mapped there); this table only closes the gap for the count family, whose triggers
|
|
643
|
-
* (AGGREGATE_TRIGGERS) don't include the "tally the classes"/"total number of classes"
|
|
644
|
-
* register. Each key is also kept OUT of the drop pass (ask.mjs treats a synonym key as
|
|
645
|
-
* meaningful) so it survives to be normalised rather than dropped as unmatched. The
|
|
646
|
-
* rewrite is guarded by ask.mjs (never applied to a token that resolves to a graph
|
|
647
|
-
* entity), so a symbol named "total" is never bent into "count". */
|
|
648
|
-
export const CASCADE_SYNONYMS = Object.freeze({
|
|
649
|
-
tally: "count", tallies: "count", sum: "count", total: "count", totals: "count",
|
|
650
|
-
});
|
|
651
|
-
|
|
652
|
-
/** Explicit help / orientation requests — when the WHOLE query is one of these, ask.mjs
|
|
653
|
-
* shows the rephrase hint DIRECTLY (the honest bottom of the cascade, reached on
|
|
654
|
-
* demand) rather than pretending to answer or running the relaxation loop. A closed
|
|
655
|
-
* set matched against the whole normalized query only, so "which functions call help"
|
|
656
|
-
* (a real question about a symbol named "help") is untouched. Standalone greetings and
|
|
657
|
-
* the chat "/help" command are chat.mjs's own surface; this is the bare CLI/MCP ask()
|
|
658
|
-
* entry point's equivalent. */
|
|
659
|
-
export const HELP_TRIGGERS = Object.freeze([
|
|
660
|
-
"help", "help me", "how do i ask", "how do i use this", "what can i ask",
|
|
661
|
-
"what can you ask", "usage", "commands", "examples", "syntax", "options",
|
|
662
|
-
]);
|
|
663
|
-
|
|
664
|
-
// ---- omitted-on-purpose (judgment calls, not oversights) -------------------
|
|
665
|
-
// "runs"/"executes" (calls) are common English words with many non-code
|
|
666
|
-
// senses — accepted anyway, formal-template AND keyword-spotting alike,
|
|
667
|
-
// because a misparse costs nothing beyond an honest object-miss
|
|
668
|
-
// (resolveObject never guesses); the risk is bounded by the render layer,
|
|
669
|
-
// not by narrowing the vocabulary.
|
|
670
|
-
// NOT added: "needs"/"wants" for imports (too weakly code-specific — "which
|
|
671
|
-
// modules need auth" reads as a feature request, not a graph query, in a way
|
|
672
|
-
// "which modules depend on auth" doesn't); "wraps"/"decorates" for calls (a
|
|
673
|
-
// real but distinct relationship codegraph.mjs doesn't classify separately —
|
|
674
|
-
// adding the phrase would silently misroute it onto plain call edges);
|
|
675
|
-
// "belongs to" for contains (already claimed by a hypothetical membership
|
|
676
|
-
// verb elsewhere — kept out to avoid a future collision if one is added).
|
|
677
|
-
// NOT added: a cochange gerund ("co-changing with") — every cochange phrase
|
|
678
|
-
// is already 2-3 words with its own internal "-ing"/"-s" (e.g. "changes
|
|
679
|
-
// alongside"), so g-drop normalization has no bare stem to dialectally
|
|
680
|
-
// contract in the first place; only relations with a genuinely bare-verb
|
|
681
|
-
// casual form ("call", "touch") needed one.
|
|
682
|
-
// WRONG_WORDS not mapped (judgment calls): "script(s)" (routinely names a real
|
|
683
|
-
// module/identifier — rewriting it could corrupt an object term, and file/files
|
|
684
|
-
// already covers the honest synonym); "package(s)" (a genuinely coarser grain
|
|
685
|
-
// this graph doesn't model — mapping it to module would silently answer a
|
|
686
|
-
// different question than the one asked); "fn" (too short and too often a real
|
|
687
|
-
// identifier fragment to rewrite at a word boundary).
|