@polycode-projects/the-mechanical-code-talker 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -3
- package/ROADMAP.md +416 -3
- package/bin/tmct.mjs +308 -12
- package/corpus/README.md +52 -0
- package/corpus/conceptnet/LICENSE-NOTICE +37 -0
- package/corpus/conceptnet/README.md +103 -0
- package/corpus/conceptnet/fetch-slice.mjs +136 -0
- package/corpus/conceptnet/filter-dump.mjs +89 -0
- package/corpus/conceptnet/slice.jsonl +14258 -0
- package/data/phrasebook/software-phrases.txt +231 -0
- package/data/templates/grammar-rules.toml +89 -0
- package/data/templates/responses.jsonl +68 -0
- package/package.json +40 -3
- package/src/ask-nlp.mjs +22 -10
- package/src/ask-vocab.mjs +35 -1
- package/src/ask.mjs +171 -494
- package/src/chat.mjs +709 -81
- package/src/corpus/conceptnet-map.toml +251 -0
- package/src/corpus/conceptnet.mjs +167 -0
- package/src/corpus/templates.mjs +188 -0
- package/src/finish.mjs +443 -0
- package/src/grammar/ace.mjs +341 -0
- package/src/grammar/assert.mjs +40 -0
- package/src/grammar/lexicon-core.json +287 -0
- package/src/grammar/lexicon.mjs +202 -0
- package/src/hash.mjs +32 -0
- package/src/index.mjs +21 -5
- package/src/init.mjs +264 -0
- package/src/interpret/fuzzy.mjs +89 -0
- package/src/interpret/merge.mjs +148 -0
- package/src/interpret/normalize.mjs +151 -0
- package/src/interpret/pipeline.mjs +112 -0
- package/src/interpret/strategies/grammar.mjs +137 -0
- package/src/interpret/strategies/keywords.mjs +241 -0
- package/src/interpret/strategies/noise-strip.mjs +114 -0
- package/src/memory/blocks.mjs +221 -0
- package/src/memory/core.mjs +533 -0
- package/src/memory/fold.mjs +0 -0
- package/src/memory/inspect.mjs +141 -0
- package/src/memory/trust.mjs +113 -0
- package/src/prose-nlp.mjs +14 -16
- package/src/providers/bootstrap.mjs +24 -0
- package/src/providers/fixture.mjs +118 -0
- package/src/providers/graph-service.mjs +312 -0
- package/src/repository-interface.mjs +318 -0
- package/src/server.mjs +44 -28
- package/src/sessions.mjs +137 -4
- package/src/source.mjs +44 -5
- package/src/syllogise.mjs +0 -0
- package/src/toml-config.mjs +14 -0
- package/src/tui/app.mjs +173 -0
- package/src/wink-model.mjs +74 -0
- package/bin/cli.mjs +0 -226
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# software-phrases.txt — the SE phrase book (ROADMAP items 4+7).
|
|
2
|
+
#
|
|
3
|
+
# One phrase pattern per line; {x}/{y} are entity slots the matcher binds to
|
|
4
|
+
# names in the graph. Lines starting with `~` declare a SYNONYM FAMILY: words
|
|
5
|
+
# and short phrases the matcher may treat as interchangeable when normalizing
|
|
6
|
+
# input. `#` starts a comment; blank lines are ignored.
|
|
7
|
+
# Parsed by src/corpus/templates.mjs loadPhrasebook().
|
|
8
|
+
|
|
9
|
+
# --- synonym families: the interchangeable vocabulary of asking about code ---
|
|
10
|
+
~ call, invoke, use, execute, run, trigger, talk to
|
|
11
|
+
~ import, include, require, pull in, depend on, load
|
|
12
|
+
~ module, file, source file, unit
|
|
13
|
+
~ function, fn, func, routine, procedure, method
|
|
14
|
+
~ class, type, struct, record, interface
|
|
15
|
+
~ test, spec, unit test, test case, check
|
|
16
|
+
~ bug, defect, fault, issue, problem, glitch
|
|
17
|
+
~ fix, repair, patch, resolve, correct
|
|
18
|
+
~ change, modify, edit, touch, update, alter, rework
|
|
19
|
+
~ delete, remove, drop, kill, strip out, get rid of
|
|
20
|
+
~ create, add, make, introduce, write, define
|
|
21
|
+
~ rename, relabel, move, relocate
|
|
22
|
+
~ commit, change set, checkin, revision
|
|
23
|
+
~ author, committer, contributor, developer, dev, engineer, programmer
|
|
24
|
+
~ big, large, huge, long, giant
|
|
25
|
+
~ small, tiny, short, little, lean
|
|
26
|
+
~ recent, latest, newest, last, fresh
|
|
27
|
+
~ old, oldest, ancient, stale, legacy
|
|
28
|
+
~ broken, failing, red, busted, dead
|
|
29
|
+
~ working, passing, green, healthy, fine
|
|
30
|
+
~ central, core, important, key, load-bearing, critical
|
|
31
|
+
~ unused, dead, orphaned, abandoned, unreferenced
|
|
32
|
+
~ caller, call site, consumer, client
|
|
33
|
+
~ callee, target, dependency
|
|
34
|
+
~ parent, superclass, base class, ancestor
|
|
35
|
+
~ child, subclass, derived class, descendant
|
|
36
|
+
~ member, field, attribute, property
|
|
37
|
+
~ argument, parameter, param, arg, input
|
|
38
|
+
~ return, result, output, yield
|
|
39
|
+
~ error, exception, failure, crash, panic
|
|
40
|
+
~ codebase, repo, repository, project, source tree, code
|
|
41
|
+
|
|
42
|
+
# --- call graph: what calls what ---
|
|
43
|
+
what calls {x}
|
|
44
|
+
what does {x} call
|
|
45
|
+
who calls {x}
|
|
46
|
+
who is calling {x}
|
|
47
|
+
which functions call {x}
|
|
48
|
+
which modules call {x}
|
|
49
|
+
what invokes {x}
|
|
50
|
+
callers of {x}
|
|
51
|
+
call sites of {x}
|
|
52
|
+
where is {x} called
|
|
53
|
+
where is {x} called from
|
|
54
|
+
is {x} called anywhere
|
|
55
|
+
is {x} ever called
|
|
56
|
+
does anything call {x}
|
|
57
|
+
does {x} call {y}
|
|
58
|
+
what talks to {x}
|
|
59
|
+
what does {x} talk to
|
|
60
|
+
what depends on {x}
|
|
61
|
+
what does {x} depend on
|
|
62
|
+
show me the call graph around {x}
|
|
63
|
+
|
|
64
|
+
# --- imports and dependencies ---
|
|
65
|
+
who imports {x}
|
|
66
|
+
what imports {x}
|
|
67
|
+
which modules import {x}
|
|
68
|
+
what does {x} import
|
|
69
|
+
where is {x} imported
|
|
70
|
+
is {x} imported anywhere
|
|
71
|
+
does {x} import {y}
|
|
72
|
+
what requires {x}
|
|
73
|
+
what uses {x}
|
|
74
|
+
what does {x} use
|
|
75
|
+
what pulls in {x}
|
|
76
|
+
dependencies of {x}
|
|
77
|
+
dependents of {x}
|
|
78
|
+
what breaks if {x} changes
|
|
79
|
+
what would be affected by changing {x}
|
|
80
|
+
impact of changing {x}
|
|
81
|
+
blast radius of {x}
|
|
82
|
+
|
|
83
|
+
# --- definition and location: where things live ---
|
|
84
|
+
where is {x}
|
|
85
|
+
where is {x} defined
|
|
86
|
+
where does {x} live
|
|
87
|
+
which file defines {x}
|
|
88
|
+
which module defines {x}
|
|
89
|
+
what is defined in {x}
|
|
90
|
+
what does {x} define
|
|
91
|
+
what lives in {x}
|
|
92
|
+
find {x}
|
|
93
|
+
show me {x}
|
|
94
|
+
is there a {x}
|
|
95
|
+
do we have a {x}
|
|
96
|
+
does {x} exist
|
|
97
|
+
where is {x} importable from
|
|
98
|
+
what does {x} export
|
|
99
|
+
what is the public api of {x}
|
|
100
|
+
what is in the {x} package
|
|
101
|
+
|
|
102
|
+
# --- description: what things are ---
|
|
103
|
+
what is {x}
|
|
104
|
+
what is {x} for
|
|
105
|
+
what does {x} do
|
|
106
|
+
describe {x}
|
|
107
|
+
tell me about {x}
|
|
108
|
+
explain {x}
|
|
109
|
+
what kind of thing is {x}
|
|
110
|
+
is {x} a module or a function
|
|
111
|
+
what type is {x}
|
|
112
|
+
what does {x} return
|
|
113
|
+
what arguments does {x} take
|
|
114
|
+
what parameters does {x} take
|
|
115
|
+
what is the signature of {x}
|
|
116
|
+
what exceptions does {x} throw
|
|
117
|
+
what does {x} raise
|
|
118
|
+
what does {x} catch
|
|
119
|
+
is {x} public or private
|
|
120
|
+
is {x} deprecated
|
|
121
|
+
|
|
122
|
+
# --- structure: classes, members, inheritance ---
|
|
123
|
+
what does {x} contain
|
|
124
|
+
what members does {x} have
|
|
125
|
+
what methods does {x} have
|
|
126
|
+
what fields does {x} have
|
|
127
|
+
what is inside {x}
|
|
128
|
+
what does {x} inherit from
|
|
129
|
+
what extends {x}
|
|
130
|
+
what subclasses {x}
|
|
131
|
+
subclasses of {x}
|
|
132
|
+
superclass of {x}
|
|
133
|
+
parents of {x}
|
|
134
|
+
children of {x}
|
|
135
|
+
is {x} a subclass of {y}
|
|
136
|
+
what implements {x}
|
|
137
|
+
implementations of {x}
|
|
138
|
+
|
|
139
|
+
# --- tests ---
|
|
140
|
+
is {x} tested
|
|
141
|
+
does {x} have tests
|
|
142
|
+
what tests {x}
|
|
143
|
+
what tests cover {x}
|
|
144
|
+
which tests exercise {x}
|
|
145
|
+
where are the tests for {x}
|
|
146
|
+
test coverage of {x}
|
|
147
|
+
what does {x} test
|
|
148
|
+
is there a test for {x}
|
|
149
|
+
how well tested is {x}
|
|
150
|
+
what has no tests
|
|
151
|
+
which modules are untested
|
|
152
|
+
do the tests pass
|
|
153
|
+
are the tests green
|
|
154
|
+
|
|
155
|
+
# --- history: commits, authors, change ---
|
|
156
|
+
who wrote {x}
|
|
157
|
+
who authored {x}
|
|
158
|
+
who last touched {x}
|
|
159
|
+
who changed {x}
|
|
160
|
+
when was {x} last changed
|
|
161
|
+
when was {x} added
|
|
162
|
+
what changed recently
|
|
163
|
+
what changed in the last commit
|
|
164
|
+
what did {x} change
|
|
165
|
+
what commits touched {x}
|
|
166
|
+
history of {x}
|
|
167
|
+
how often does {x} change
|
|
168
|
+
what changes together with {x}
|
|
169
|
+
what usually changes with {x}
|
|
170
|
+
is {x} new
|
|
171
|
+
is {x} stale
|
|
172
|
+
who knows about {x}
|
|
173
|
+
who owns {x}
|
|
174
|
+
|
|
175
|
+
# --- size, count, shape ---
|
|
176
|
+
how many modules are there
|
|
177
|
+
how many functions are there
|
|
178
|
+
how many classes are there
|
|
179
|
+
how many tests are there
|
|
180
|
+
how big is {x}
|
|
181
|
+
how big is the codebase
|
|
182
|
+
how many lines is {x}
|
|
183
|
+
what is the biggest module
|
|
184
|
+
what is the biggest function
|
|
185
|
+
what is the most complex module
|
|
186
|
+
what is the most central module
|
|
187
|
+
what is the most imported module
|
|
188
|
+
what is the most called function
|
|
189
|
+
what has the most dependencies
|
|
190
|
+
what has no dependencies
|
|
191
|
+
what is unused
|
|
192
|
+
what is dead code
|
|
193
|
+
list the modules
|
|
194
|
+
list the classes
|
|
195
|
+
list everything you know about {x}
|
|
196
|
+
|
|
197
|
+
# --- bugs, quality, health ---
|
|
198
|
+
is {x} broken
|
|
199
|
+
why is {x} failing
|
|
200
|
+
what is wrong with {x}
|
|
201
|
+
does {x} have known bugs
|
|
202
|
+
is {x} safe to change
|
|
203
|
+
is {x} safe to delete
|
|
204
|
+
what is risky about {x}
|
|
205
|
+
what smells in {x}
|
|
206
|
+
is {x} too big
|
|
207
|
+
does {x} do too much
|
|
208
|
+
|
|
209
|
+
# --- memory: what tmct itself was told ---
|
|
210
|
+
what did i tell you about {x}
|
|
211
|
+
what do you know about {x}
|
|
212
|
+
what do you remember about {x}
|
|
213
|
+
what have i told you
|
|
214
|
+
what did i ask you before
|
|
215
|
+
did i mention {x}
|
|
216
|
+
remember that {x}
|
|
217
|
+
forget about {x}
|
|
218
|
+
what did you just say
|
|
219
|
+
what was your last answer
|
|
220
|
+
what did we talk about
|
|
221
|
+
summarise this session
|
|
222
|
+
|
|
223
|
+
# --- meta: about the graph and tmct ---
|
|
224
|
+
what can you answer
|
|
225
|
+
what do you know
|
|
226
|
+
how much do you know
|
|
227
|
+
what is in your graph
|
|
228
|
+
when was your graph built
|
|
229
|
+
where does your graph come from
|
|
230
|
+
what can i ask you
|
|
231
|
+
help me ask a better question
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# grammar-rules.toml — the data-driven grammar-rule table (Phase 7, lever 2)
|
|
2
|
+
# (PLAN_RESPONSE_FINISHING.md, "The grammar pass (lever 2)").
|
|
3
|
+
#
|
|
4
|
+
# Each [[rule]] is a corrective grammar rule applied by applyGrammar() in
|
|
5
|
+
# src/finish.mjs over the PROSE spans of a segmented answer — NEVER the flat
|
|
6
|
+
# string, and NEVER a protected span (entity / path / number / code / provenance
|
|
7
|
+
# / receipt). The engine reads STRUCTURE, never guesses from surface: an article
|
|
8
|
+
# rule that would touch the word inside the following protected span refuses to
|
|
9
|
+
# fire, agreement reads the following number's value, and so on.
|
|
10
|
+
#
|
|
11
|
+
# CONTRACT (the plan's law): a rule's NEUTRAL behaviour is BYTE-STABLE. The only
|
|
12
|
+
# byte changes a rule may introduce are GENUINE fixes to defects tmct itself
|
|
13
|
+
# generates ("a artifact"). `kind` selects the built-in handler; `enabled=false`
|
|
14
|
+
# PARKS a rule out of the live answer path; the remaining keys are that handler's
|
|
15
|
+
# applicability conditions + parameters. Rules apply in file order; the set is
|
|
16
|
+
# chosen to commute so finish() is idempotent: finish(finish(x)) === finish(x).
|
|
17
|
+
#
|
|
18
|
+
# SEQUENCING (PLAN_RESPONSE_FINISHING.md, "one grammar rule per tuning cycle"):
|
|
19
|
+
# only ARTICLE-SELECTION is live this cycle — it fixes a genuine defect with a
|
|
20
|
+
# narrow, safe blast radius. AGREEMENT, CAPITALISATION, LIST and TERMINAL are
|
|
21
|
+
# fully implemented and golden-tested IN ISOLATION, but PARKED (enabled=false):
|
|
22
|
+
# each rewrites established product bytes (tmct's lowercase openers and repeated
|
|
23
|
+
# "and" joins are an intentional VOICE, not a grammar defect), so activating them
|
|
24
|
+
# is a per-rule tuning-cycle decision with its own bench + showcase reconcile,
|
|
25
|
+
# not a blanket flip. `enabled=false` keeps them inert in finish(); the goldens
|
|
26
|
+
# force-enable each rule to prove its behaviour independent of the live flag.
|
|
27
|
+
|
|
28
|
+
# 1. Article selection — a/an by the following word's phonetic onset. The live
|
|
29
|
+
# defect this fixes: the assert echo "every module is a artifact" -> "an
|
|
30
|
+
# artifact". Reads the next word (whether in-span or the leading token of the
|
|
31
|
+
# following protected span); refuses at a boundary it cannot read safely.
|
|
32
|
+
[[rule]]
|
|
33
|
+
id = "article-selection"
|
|
34
|
+
kind = "article"
|
|
35
|
+
enabled = true
|
|
36
|
+
registers = [] # [] = every register
|
|
37
|
+
description = "a/an agreement with the following word's phonetic onset"
|
|
38
|
+
# Spelling-vowel words that begin with a CONSONANT sound (take 'a').
|
|
39
|
+
consonant_sound_vowels = ["uni", "use", "user", "usa", "usu", "ubi", "eu", "ewe", "one", "once"]
|
|
40
|
+
# Spelling-consonant words that begin with a VOWEL sound (take 'an'): silent h.
|
|
41
|
+
vowel_sound_consonants = ["hour", "honest", "honour", "honor", "heir", "herb"]
|
|
42
|
+
|
|
43
|
+
# 2. Subject–verb agreement — an existential copula agrees with the count that
|
|
44
|
+
# follows it ("there is 3 classes" -> "there are 3 classes"; "there are 1
|
|
45
|
+
# class" -> "there is 1 class"). Structure-driven: the plurality is READ from
|
|
46
|
+
# the following number span's value (or a protected span's explicit `plural`
|
|
47
|
+
# flag), never guessed. Neutral on already-correct agreement.
|
|
48
|
+
[[rule]]
|
|
49
|
+
id = "subject-verb-agreement"
|
|
50
|
+
kind = "agreement"
|
|
51
|
+
enabled = false # PARKED — implemented + golden-tested, not live this cycle
|
|
52
|
+
registers = []
|
|
53
|
+
description = "existential copula agrees with the following count/plurality"
|
|
54
|
+
singular = ["is", "was", "has"]
|
|
55
|
+
plural = ["are", "were", "have"]
|
|
56
|
+
|
|
57
|
+
# 3. Sentence capitalisation — capitalise the first alphabetic character of a
|
|
58
|
+
# sentence-initial prose span. Never fires when the answer opens on a
|
|
59
|
+
# protected span (a path/entity opener is left exactly as grounded).
|
|
60
|
+
[[rule]]
|
|
61
|
+
id = "sentence-capitalisation"
|
|
62
|
+
kind = "capitalise"
|
|
63
|
+
enabled = false # PARKED — implemented + golden-tested, not live this cycle
|
|
64
|
+
registers = []
|
|
65
|
+
description = "capitalise the first alphabetic of a prose-initial span"
|
|
66
|
+
|
|
67
|
+
# 4. List punctuation — a series joined by repeated " and " connectives becomes
|
|
68
|
+
# a comma series with a single terminal conjunction ("a and b and c" -> "a, b
|
|
69
|
+
# and c"). Operates ONLY on the prose connective spans, never the entity spans
|
|
70
|
+
# they join; a two-item list ("a and b") is already correct and untouched.
|
|
71
|
+
[[rule]]
|
|
72
|
+
id = "list-punctuation"
|
|
73
|
+
kind = "list"
|
|
74
|
+
enabled = false # PARKED — implemented + golden-tested, not live this cycle
|
|
75
|
+
registers = []
|
|
76
|
+
description = "repeated 'and' joins in a 3+ item series become a comma series"
|
|
77
|
+
connective = " and "
|
|
78
|
+
separator = ", "
|
|
79
|
+
|
|
80
|
+
# 5. Terminal punctuation — exactly one sentence-final stop: a run of 2+ trailing
|
|
81
|
+
# stops in the final prose span collapses to one ("done.." -> "done."). Adds
|
|
82
|
+
# nothing where a fragment/list answer legitimately ends without a stop.
|
|
83
|
+
[[rule]]
|
|
84
|
+
id = "terminal-punctuation"
|
|
85
|
+
kind = "terminal"
|
|
86
|
+
enabled = false # PARKED — implemented + golden-tested, not live this cycle
|
|
87
|
+
registers = []
|
|
88
|
+
description = "collapse a run of trailing sentence stops to a single stop"
|
|
89
|
+
stops = [".", "!", "?"]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{"id":"describe-entity-terse","class":"describe","register":"terse","template":"{subject}: {kind} in {location}."}
|
|
2
|
+
{"id":"describe-entity-friendly","class":"describe","register":"friendly","template":"{subject} is a {kind} living in {location}."}
|
|
3
|
+
{"id":"describe-entity-with-doc","class":"describe","register":"friendly","template":"{subject} is a {kind} in {location} — \"{doc}\"."}
|
|
4
|
+
{"id":"describe-module-imports","class":"describe","register":"friendly","template":"{subject} imports {objects}."}
|
|
5
|
+
{"id":"describe-module-imported-by","class":"describe","register":"friendly","template":"{subject} is imported by {objects}."}
|
|
6
|
+
{"id":"describe-callers","class":"describe","register":"friendly","template":"{subject} is called by {objects}."}
|
|
7
|
+
{"id":"describe-callers-terse","class":"describe","register":"terse","template":"{subject} <- {objects}."}
|
|
8
|
+
{"id":"describe-callees","class":"describe","register":"friendly","template":"{subject} calls {objects}."}
|
|
9
|
+
{"id":"describe-members","class":"describe","register":"friendly","template":"{subject} contains {objects}."}
|
|
10
|
+
{"id":"describe-superclass","class":"describe","register":"friendly","template":"{subject} inherits from {object}."}
|
|
11
|
+
{"id":"describe-tested-by","class":"describe","register":"friendly","template":"{subject} is exercised by {objects}."}
|
|
12
|
+
{"id":"describe-untested","class":"describe","register":"friendly","template":"I can't see any test that imports {subject} — that may just mean the coverage is indirect."}
|
|
13
|
+
{"id":"describe-history","class":"describe","register":"friendly","template":"{subject} was last touched by {commit} ({when}): \"{message}\"."}
|
|
14
|
+
{"id":"describe-relation-fact","class":"describe","register":"terse","template":"{subject} {predicate} {object}."}
|
|
15
|
+
{"id":"describe-isa-fact","class":"describe","register":"friendly","template":"As I understand it, a {subject} is a kind of {object}."}
|
|
16
|
+
{"id":"count-plain","class":"count","register":"terse","template":"{count} {noun}."}
|
|
17
|
+
{"id":"count-sentence","class":"count","register":"friendly","template":"There are {count} {noun} in {scope}."}
|
|
18
|
+
{"id":"count-one","class":"count","register":"friendly","template":"There is exactly one {noun} in {scope}: {subject}."}
|
|
19
|
+
{"id":"count-zero","class":"count","register":"friendly","template":"I can't find any {noun} in {scope}."}
|
|
20
|
+
{"id":"count-with-sample","class":"count","register":"friendly","template":"{count} {noun} in {scope} — for example {examples}."}
|
|
21
|
+
{"id":"count-compared","class":"count","register":"friendly","template":"{count} {noun} — {comparison} for a codebase of this size."}
|
|
22
|
+
{"id":"miss-plain","class":"miss","register":"terse","template":"No match for \"{query}\"."}
|
|
23
|
+
{"id":"miss-honest","class":"miss","register":"friendly","template":"I couldn't ground \"{query}\" in anything I know. I'd rather say so than guess."}
|
|
24
|
+
{"id":"miss-rephrase-name","class":"miss","register":"friendly","template":"I don't recognise \"{query}\". If you name a module, function, or class I know about, I can work from there."}
|
|
25
|
+
{"id":"miss-rephrase-pattern","class":"miss","register":"friendly","template":"\"{query}\" didn't match anything. Try a shape like \"{example}\" — that's a question I can answer precisely."}
|
|
26
|
+
{"id":"miss-nearest","class":"miss","register":"friendly","template":"Nothing matches \"{query}\" exactly. The nearest name I know is {nearest} — is that what you meant?"}
|
|
27
|
+
{"id":"miss-nearest-terse","class":"miss","register":"terse","template":"No \"{query}\". Nearest: {nearest}."}
|
|
28
|
+
{"id":"miss-empty-graph","class":"miss","register":"friendly","template":"My graph is empty right now, so I can't answer \"{query}\" yet. Tell me things and I'll remember them."}
|
|
29
|
+
{"id":"miss-out-of-domain","class":"miss","register":"friendly","template":"That sounds like it's outside my patch — I only really know about {scope}. Ask me about the code and I'm much more useful."}
|
|
30
|
+
{"id":"ambiguity-two","class":"ambiguity","register":"friendly","template":"That could go two ways. If you mean {a} then {aAnswer}; if you mean {b} then {bAnswer}."}
|
|
31
|
+
{"id":"ambiguity-two-terse","class":"ambiguity","register":"terse","template":"{a}: {aAnswer} / {b}: {bAnswer}."}
|
|
32
|
+
{"id":"ambiguity-three","class":"ambiguity","register":"friendly","template":"I see three readings. If you mean {a} then {aAnswer}; if you mean {b} then {bAnswer}; if you mean {c} then {cAnswer}."}
|
|
33
|
+
{"id":"ambiguity-name-clash","class":"ambiguity","register":"friendly","template":"\"{query}\" names more than one thing here: {candidates}. Which one do you mean?"}
|
|
34
|
+
{"id":"ambiguity-name-clash-terse","class":"ambiguity","register":"terse","template":"\"{query}\" is ambiguous: {candidates}."}
|
|
35
|
+
{"id":"ambiguity-class-split","class":"ambiguity","register":"friendly","template":"Reading \"{query}\" as a {a} gives one answer, reading it as a {b} gives another. Say which and I'll commit."}
|
|
36
|
+
{"id":"assume-scope","class":"assumption","register":"friendly","template":"I'll assume you're asking about {assumed} — say otherwise and I'll drop that."}
|
|
37
|
+
{"id":"assume-scope-terse","class":"assumption","register":"terse","template":"Assuming {assumed}."}
|
|
38
|
+
{"id":"assume-spelling","class":"assumption","register":"friendly","template":"I read \"{query}\" as {assumed} (closest name I know). {answer}"}
|
|
39
|
+
{"id":"assume-this-repo","class":"assumption","register":"friendly","template":"I'm assuming \"{query}\" is about this repository. {answer}"}
|
|
40
|
+
{"id":"assume-latest","class":"assumption","register":"friendly","template":"You didn't say which {noun}, so I took the most recent one: {assumed}."}
|
|
41
|
+
{"id":"assume-singular","class":"assumption","register":"friendly","template":"Several things match; I picked the strongest, {assumed}. The runners-up were {others}."}
|
|
42
|
+
{"id":"recall-plain","class":"recall","register":"friendly","template":"You told me earlier that {fact}."}
|
|
43
|
+
{"id":"recall-plain-terse","class":"recall","register":"terse","template":"Earlier: {fact}."}
|
|
44
|
+
{"id":"recall-with-when","class":"recall","register":"friendly","template":"Earlier in this session ({when}) you said \"{utterance}\"."}
|
|
45
|
+
{"id":"recall-prior-session","class":"recall","register":"friendly","template":"In a previous session you told me that {fact} — I'm going on that."}
|
|
46
|
+
{"id":"recall-corpus","class":"recall","register":"friendly","template":"My corpus says {fact} — that's background knowledge, not something you told me."}
|
|
47
|
+
{"id":"recall-conflict","class":"recall","register":"friendly","template":"Careful — you told me earlier that {fact}, which doesn't sit well with \"{query}\". Which should I keep?"}
|
|
48
|
+
{"id":"recall-similar-question","class":"recall","register":"friendly","template":"You asked something similar before (\"{utterance}\") and the answer was: {answer}"}
|
|
49
|
+
{"id":"recall-nothing","class":"recall","register":"friendly","template":"You haven't told me anything about {subject} yet."}
|
|
50
|
+
{"id":"stored-fact","class":"stored","register":"friendly","template":"Noted: {subject} {predicate} {object}. I'll remember that."}
|
|
51
|
+
{"id":"stored-fact-terse","class":"stored","register":"terse","template":"Stored: {subject} {predicate} {object}."}
|
|
52
|
+
{"id":"stored-duplicate","class":"stored","register":"friendly","template":"I already knew that {subject} {predicate} {object} — nothing new to store."}
|
|
53
|
+
{"id":"nudge-precision","class":"nudge","register":"friendly","template":"The closer you get to a shape like \"{example}\", the sharper my answer gets."}
|
|
54
|
+
{"id":"nudge-commands","class":"nudge","register":"friendly","template":"If prose fails you, the slash commands always work — try {command}."}
|
|
55
|
+
{"id":"nudge-narrower","class":"nudge","register":"friendly","template":"That matched {count} things — too many to be useful. Narrow it with a module or class name."}
|
|
56
|
+
{"id":"conversational-greeting","class":"conversational","register":"friendly","template":"Hi. Ask me about this codebase — imports, calls, definitions, history — or /help."}
|
|
57
|
+
{"id":"conversational-greeting-hello-there","class":"conversational","register":"friendly","template":"Hello there. (A hollow voice says, \"fool.\") Ask me about this codebase, or /help."}
|
|
58
|
+
{"id":"conversational-greeting-good-morning","class":"conversational","register":"friendly","template":"Good morning. Ask me about this codebase, or /help."}
|
|
59
|
+
{"id":"conversational-greeting-good-afternoon","class":"conversational","register":"friendly","template":"Good afternoon. Ask me about this codebase, or /help."}
|
|
60
|
+
{"id":"conversational-greeting-good-evening","class":"conversational","register":"friendly","template":"Good evening. Ask me about this codebase, or /help."}
|
|
61
|
+
{"id":"conversational-thanks","class":"conversational","register":"friendly","template":"Any time. Ask another, or /help for what I can do."}
|
|
62
|
+
{"id":"conversational-farewell","class":"conversational","register":"friendly","template":"Bye — flushing the session log. Come back with a question any time."}
|
|
63
|
+
{"id":"orientation-friendly","class":"orientation","register":"friendly","template":"I answer questions about THIS codebase's structure — imports, calls, definitions,\nhistory and counts. For example:\n which modules import walk.mjs\n what calls buildContextBundle\n how many classes are there\n/help for commands, /stats for an overview of the graph."}
|
|
64
|
+
{"id":"miss-no-previous-answer","class":"miss","register":"friendly","template":"No previous answer to expand yet — ask me a question first, then say \"why\" or \"say more\"."}
|
|
65
|
+
{"id":"technical-density","class":"count","register":"technical","template":"{subject} carries {count} {noun} across {scope} — a concentration well above what a codebase of this size typically sustains ({provenance})."}
|
|
66
|
+
{"id":"technical-comparison","class":"count","register":"technical","template":"At {count} {noun}, {subject} sits {comparison} the comparable-project baseline, a divergence that reflects deliberate structure rather than measurement noise ({provenance})."}
|
|
67
|
+
{"id":"technical-superlative","class":"count","register":"technical","template":"No {noun} in {scope} is more {metric} than {subject}; it leads the next candidate by a clear margin of {count} ({provenance})."}
|
|
68
|
+
{"id":"technical-ratio","class":"count","register":"technical","template":"{subject} sustains a ratio of {count} {noun} per {unit}, placing it in the upper band for projects of comparable {scope} ({provenance})."}
|
package/package.json
CHANGED
|
@@ -1,12 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polycode-projects/the-mechanical-code-talker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "The Mechanical Code Talker (tmct) — a tolerant, offline, $0 chat surface that guides you toward precision queries about a software repository. ELIZA/PARRY-style but domain-obsessed with code. No model calls; no codebase index of its own.",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"chatbot",
|
|
9
|
+
"no-llm",
|
|
10
|
+
"offline",
|
|
11
|
+
"deterministic",
|
|
12
|
+
"eliza",
|
|
13
|
+
"parry",
|
|
14
|
+
"nlp",
|
|
15
|
+
"wink-nlp",
|
|
16
|
+
"owl",
|
|
17
|
+
"rdf",
|
|
18
|
+
"ontology",
|
|
19
|
+
"controlled-natural-language",
|
|
20
|
+
"ace",
|
|
21
|
+
"knowledge-graph",
|
|
22
|
+
"provenance",
|
|
23
|
+
"code-navigation",
|
|
24
|
+
"cli"
|
|
25
|
+
],
|
|
7
26
|
"license": "MPL-2.0",
|
|
8
27
|
"author": "Polycode Limited",
|
|
9
28
|
"homepage": "https://polycode-projects.gitlab.io/the-mechanical-code-talker/",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://gitlab.com/polycode-projects/the-mechanical-code-talker.git"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://gitlab.com/polycode-projects/the-mechanical-code-talker/-/issues"
|
|
35
|
+
},
|
|
10
36
|
"engines": {
|
|
11
37
|
"node": ">=24"
|
|
12
38
|
},
|
|
@@ -29,18 +55,29 @@
|
|
|
29
55
|
"src/",
|
|
30
56
|
"README.md",
|
|
31
57
|
"ROADMAP.md",
|
|
32
|
-
"LICENSE"
|
|
58
|
+
"LICENSE",
|
|
59
|
+
"corpus/",
|
|
60
|
+
"data/"
|
|
33
61
|
],
|
|
34
62
|
"publishConfig": {
|
|
35
63
|
"access": "public"
|
|
36
64
|
},
|
|
37
65
|
"dependencies": {
|
|
66
|
+
"ink": "^7.1.0",
|
|
67
|
+
"react": "^19.2.7",
|
|
38
68
|
"smol-toml": "^1.7.0",
|
|
39
69
|
"wink-eng-lite-web-model": "^1.8.1",
|
|
40
70
|
"wink-nlp": "^2.4.0"
|
|
41
71
|
},
|
|
42
72
|
"scripts": {
|
|
43
73
|
"test": "node --test \"test/**/*.test.mjs\"",
|
|
44
|
-
"chat": "node bin/tmct.mjs"
|
|
74
|
+
"chat": "node bin/tmct.mjs",
|
|
75
|
+
"chatbench:run": "node chatbench/run.mjs",
|
|
76
|
+
"chatbench:judge": "node chatbench/judge.mjs",
|
|
77
|
+
"audit": "npm audit --audit-level=high",
|
|
78
|
+
"audit:fix": "npm audit fix"
|
|
79
|
+
},
|
|
80
|
+
"devDependencies": {
|
|
81
|
+
"ink-testing-library": "^4.0.0"
|
|
45
82
|
}
|
|
46
83
|
}
|
package/src/ask-nlp.mjs
CHANGED
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
// the bounded edit-distance tier still work, browser and Node alike). Keeping the
|
|
10
10
|
// ~1MB CJS model out of the page is the point of the split.
|
|
11
11
|
//
|
|
12
|
-
// wink-nlp and wink-eng-lite-web-model are
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// first use and failure is cached as null: a checkout without the optional
|
|
16
|
-
// installed answers exactly like the browser bundle, it never throws.
|
|
12
|
+
// wink-nlp and wink-eng-lite-web-model are loaded through the shared leaf loader
|
|
13
|
+
// src/wink-model.mjs (Node `createRequire` fallback + a browser registration seam),
|
|
14
|
+
// so this file no longer carries its own Node-only load block. The load happens
|
|
15
|
+
// lazily on first use and failure is cached as null: a checkout without the optional
|
|
16
|
+
// deps installed answers exactly like the browser bundle, it never throws.
|
|
17
17
|
|
|
18
|
-
import {
|
|
18
|
+
import { winkInstance } from "./wink-model.mjs";
|
|
19
19
|
|
|
20
20
|
let cached; // undefined = not tried yet; null = unavailable (tried once, honestly off)
|
|
21
21
|
|
|
@@ -25,10 +25,8 @@ let cached; // undefined = not tried yet; null = unavailable (tried once, honest
|
|
|
25
25
|
export function nlpAdapter() {
|
|
26
26
|
if (cached !== undefined) return cached;
|
|
27
27
|
try {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
const model = require("wink-eng-lite-web-model");
|
|
31
|
-
const nlp = winkNLP(model);
|
|
28
|
+
const nlp = winkInstance();
|
|
29
|
+
if (!nlp) { cached = null; return cached; }
|
|
32
30
|
const its = nlp.its;
|
|
33
31
|
cached = {
|
|
34
32
|
/** Lowercase lemma of a single token ("imported" -> "import"); the word
|
|
@@ -42,6 +40,20 @@ export function nlpAdapter() {
|
|
|
42
40
|
return w.toLowerCase();
|
|
43
41
|
}
|
|
44
42
|
},
|
|
43
|
+
/** True when wink's lexicon flags the word as an English stop word
|
|
44
|
+
* ("anyway", "well", "also", …). Consulted by the noise-strip strategy
|
|
45
|
+
* (interpret/strategies/noise-strip.mjs) as its wink tier — the strategy's
|
|
46
|
+
* own KEEP set screens out the grammar's load-bearing words (which/what/
|
|
47
|
+
* does/…) BEFORE this is asked, so wink flagging a question word is
|
|
48
|
+
* harmless by construction. False on any surprise, never a throw. */
|
|
49
|
+
isStopWord(word) {
|
|
50
|
+
try {
|
|
51
|
+
const out = nlp.readDoc(String(word || "")).tokens().out(its.stopWordFlag);
|
|
52
|
+
return out[0] === true;
|
|
53
|
+
} catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
},
|
|
45
57
|
/** UPOS tags aligned to the CALLER's word array. wink re-tokenizes (it
|
|
46
58
|
* splits "walk.mjs" into three tokens), so each input word is greedily
|
|
47
59
|
* matched to the run of wink tokens that spell it and takes its FIRST
|
package/src/ask-vocab.mjs
CHANGED
|
@@ -220,6 +220,28 @@ export const MODIFIER_TO_KIND = Object.freeze({
|
|
|
220
220
|
transitively: "transitive", indirectly: "transitive",
|
|
221
221
|
});
|
|
222
222
|
|
|
223
|
+
// ---- reversible-passive participles (Cycle 6, PLAN_CYCLE_4.md) — past participles ->
|
|
224
|
+
// relation kind, for the agent-marked passive "X is <participle> by Y". Kept SEPARATE
|
|
225
|
+
// from VERB_TO_KIND on purpose: these forms are NOT standalone active verbs in this
|
|
226
|
+
// grammar ("defined" belongs to the multi-word "is defined in" and to the WHERE_MARKERS
|
|
227
|
+
// location routing; bare "inherited" has no active key), so folding them into
|
|
228
|
+
// VERB_TO_KIND would silently re-route "where is X defined" and other queries. This
|
|
229
|
+
// table is consulted ONLY by the keyword strategy's passive path, which has already
|
|
230
|
+
// confirmed a passive auxiliary AND an agent-marking "by" — so an active query is never
|
|
231
|
+
// affected. Most common participles ("imported"/"tested"/"called"/"covered") already
|
|
232
|
+
// reach VERB_TO_KIND via the lemma tier; this table backfills the two families the lemma
|
|
233
|
+
// tier can't (defines/inherits) plus the obvious siblings, so the passive works
|
|
234
|
+
// adapter-free too. ----
|
|
235
|
+
export const PASSIVE_PARTICIPLE_TO_KIND = Object.freeze({
|
|
236
|
+
imported: "imports", called: "calls", used: "uses",
|
|
237
|
+
tested: "tests", covered: "tests", verified: "tests", exercised: "tests", checked: "tests",
|
|
238
|
+
defined: "defines", declared: "defines",
|
|
239
|
+
inherited: "inherits", extended: "inherits", subclassed: "inherits",
|
|
240
|
+
contained: "contains",
|
|
241
|
+
exported: "reexports", "re-exported": "reexports", exposed: "reexports",
|
|
242
|
+
touched: "touches", changed: "touches", modified: "touches", edited: "touches", updated: "touches",
|
|
243
|
+
});
|
|
244
|
+
|
|
223
245
|
// ---- §3.5 normalization — contractions/informal spellings that would otherwise
|
|
224
246
|
// block a match, expanded BEFORE parsing (BOTH the anchored-template strategy
|
|
225
247
|
// and the independent keyword-spotting strategy see the same normalized text —
|
|
@@ -295,7 +317,13 @@ export const MISSPELLINGS = Object.freeze({
|
|
|
295
317
|
"tets": "tests",
|
|
296
318
|
// grammar anchor words
|
|
297
319
|
"whcih": "which", "wich": "which", "whihc": "which",
|
|
298
|
-
"
|
|
320
|
+
// "wat" (chatbench cycle 2, tf-wat-calls): the internet-casual spelling of
|
|
321
|
+
// "what" — neither curated noise nor a restorable trigger typo, so "wat calls
|
|
322
|
+
// fnAlpha" used to die as "couldn't resolve one of the terms". Restored here
|
|
323
|
+
// so BOTH parse strategies and the relaxation cascade see the canonical
|
|
324
|
+
// anchor; the correction regex's dotted-extension guard keeps a module
|
|
325
|
+
// literally named "wat.mjs" untouched, same residual trade as every entry.
|
|
326
|
+
"waht": "what", "wat": "what",
|
|
299
327
|
"dose": "does", "doess": "does",
|
|
300
328
|
"teh": "the",
|
|
301
329
|
// aggregate/list TRIGGER words (2026-07-02, trigger-typo work) — a typo of a count
|
|
@@ -626,6 +654,12 @@ export const CASCADE_NOISE = Object.freeze([
|
|
|
626
654
|
// vocatives / terms of address (the "matey" of the worked example, and its kin)
|
|
627
655
|
"matey", "mate", "buddy", "pal", "dude", "man", "bro", "bru", "fam",
|
|
628
656
|
"friend", "sir", "maam", "folks", "guys", "everyone", "dear",
|
|
657
|
+
// the product's OWN name used as an address (chatbench cycle 2, ns-hey-tmct:
|
|
658
|
+
// "hey tmct, what calls fnAlpha thanks") — a vocative like "matey", stripped
|
|
659
|
+
// by the same rules: relaxParse's resolvesExact guard still protects a module
|
|
660
|
+
// literally named "tmct", and noise-strip's template/keyword-spot acceptance
|
|
661
|
+
// bounds the cost of a mid-question strip to an honest object-miss.
|
|
662
|
+
"tmct",
|
|
629
663
|
// presentation frames — the keyword-spotting strategy's blind spot: the
|
|
630
664
|
// compositional grammar skips these as FRAME_WORDS, but "show me what imports X"
|
|
631
665
|
// otherwise decomposes (via keyword-spot) to ask{subject:"show me"}. Stripping
|