@polycode-projects/the-mechanical-code-talker 1.8.17 → 1.8.20
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/package.json +1 -1
- package/src/ask.mjs +38 -16
- package/src/chat.mjs +33 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polycode-projects/the-mechanical-code-talker",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.20",
|
|
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.",
|
package/src/ask.mjs
CHANGED
|
@@ -3514,22 +3514,44 @@ export function traverse(graph, parsed, { contextId = null, prev = null, pinnedO
|
|
|
3514
3514
|
widenNote = `, widened to ${siblingClass} subjects (no ${entityType} recorded)`;
|
|
3515
3515
|
}
|
|
3516
3516
|
}
|
|
3517
|
-
// "touches" up-refine composability (HANDOVER 2026-07-12, Class-to-
|
|
3518
|
-
// up-refinement
|
|
3519
|
-
//
|
|
3520
|
-
//
|
|
3521
|
-
//
|
|
3522
|
-
//
|
|
3523
|
-
// "
|
|
3524
|
-
//
|
|
3525
|
-
//
|
|
3526
|
-
//
|
|
3527
|
-
//
|
|
3528
|
-
//
|
|
3529
|
-
//
|
|
3530
|
-
//
|
|
3531
|
-
//
|
|
3532
|
-
|
|
3517
|
+
// "touches"/"calls" up-refine composability (HANDOVER 2026-07-12, Class-to-
|
|
3518
|
+
// module up-refinement; extended to `calls` in the 2026-07-12 follow-up —
|
|
3519
|
+
// "who calls Router" wrongly returned empty for a Class whose calls are only
|
|
3520
|
+
// recorded at module-coarse grain): an EMPTY touchesSymbol/callsSymbol lookup
|
|
3521
|
+
// on a resolved CLASS is not decisive the way it is for a Function/Method — a
|
|
3522
|
+
// Class reads naturally as "the file/unit that holds it", so "who touched
|
|
3523
|
+
// <Class>"/"who calls <Class>" with no recorded symbol-precise edge should
|
|
3524
|
+
// still answer from the class's containing module's real touches/calls,
|
|
3525
|
+
// rather than a confident-looking-but-possibly-wrong "nothing touched/calls
|
|
3526
|
+
// it". Deliberately NOT widened to every FINE_ENTITY_TYPES member: "how many
|
|
3527
|
+
// commits touched fnAlpha" (a Function) is pinned elsewhere (ask-combo.test.mjs's
|
|
3528
|
+
// grain-aware COUNT lever) to stay an honest 0 rather than a module-grain
|
|
3529
|
+
// false hit — symbol-level counting precision for functions/methods is a
|
|
3530
|
+
// deliberate, separate guarantee this change must not erode.
|
|
3531
|
+
//
|
|
3532
|
+
// Up-refine eligibility is gated on the Class having NO recorded `contains`
|
|
3533
|
+
// members: a class the extractor actually populated (Widget, Logger — both
|
|
3534
|
+
// carry real `contains` edges) reads as a fully-modeled unit whose own empty
|
|
3535
|
+
// symbol-grain scan IS the honest answer; a class with zero recorded members
|
|
3536
|
+
// (Router, Button — the extractor only ever saw its declaration, never a
|
|
3537
|
+
// body) is exactly the shape where the coarser module-level edge is the only
|
|
3538
|
+
// real signal recorded at all.
|
|
3539
|
+
//
|
|
3540
|
+
// Even when eligible, only actually fall through to the shared grain-aware
|
|
3541
|
+
// up-refine block below when a containing module can be resolved RIGHT NOW.
|
|
3542
|
+
// That block's own "no containing module found" case renders a DIFFERENT,
|
|
3543
|
+
// wrongGrainMiss-shaped honest miss ("'Button' resolved to the class Button,
|
|
3544
|
+
// but this question needs a module…") than the plain zero-match miss this
|
|
3545
|
+
// symbol-grain scan already renders ("No modules found whose module directly
|
|
3546
|
+
// calls Button…"). A Class with no `contains` members AND no `defines` edge
|
|
3547
|
+
// naming its module (the synthetic chatflow-tier2 fixture's Button, which the
|
|
3548
|
+
// extractor recorded a bare declaration for but never wired into `defines`)
|
|
3549
|
+
// must keep the latter, plain-miss wording — eligibility alone doesn't
|
|
3550
|
+
// guarantee the up-refine can actually complete.
|
|
3551
|
+
const upRefineEligible = (kind === "touches" || kind === "calls") && objMatch.class === "Class"
|
|
3552
|
+
&& !edgesOfKind(graph, "contains").some((e) => e.subject === objMatch.id);
|
|
3553
|
+
const upRefineModule = upRefineEligible ? graph.byId.get(moduleIdOf(graph, objMatch) || "") : null;
|
|
3554
|
+
if (matches.length || !(upRefineEligible && upRefineModule)) {
|
|
3533
3555
|
return { matches, objMatch, candidates, traversal: `${symbolKind} edges where object = ${objMatch.label}${widenNote}`, ambiguous, matchedVia };
|
|
3534
3556
|
}
|
|
3535
3557
|
}
|
package/src/chat.mjs
CHANGED
|
@@ -4501,6 +4501,13 @@ const FACT_ANSWER_CAP = 32;
|
|
|
4501
4501
|
const CAN_ASK_RE = /^(?:can|could)\s+(?:an?\s+)?([\w'-]+(?:\s+[\w'-]+)*?)\s+([a-z]+)[?.!\s]*$/i;
|
|
4502
4502
|
const WHAT_CAN_DO_RE = /^what\s+can\s+(?:an?\s+)?(.+?)\s+do[?.!\s]*$/i;
|
|
4503
4503
|
const WHAT_HAS_RE = /^what\s+has\s+(?:an?\s+)?(.+?)[?.!\s]*$/i;
|
|
4504
|
+
// "what is used for riding" / "what can be used for riding" / "what is for
|
|
4505
|
+
// riding" — the reverse-by-object mirror of BUG 1's forward reader ("what is
|
|
4506
|
+
// a tree used for"), missing until now: BUG 1 only ever filtered a KNOWN
|
|
4507
|
+
// subject's facts down to mgx:usedFor; nothing answered the reverse question
|
|
4508
|
+
// (object known, subject unknown), so it fell all the way through to the
|
|
4509
|
+
// code-graph miss cascade — actively misleading for a pure vocabulary query.
|
|
4510
|
+
const WHAT_USED_FOR_RE = /^what\s+(?:(?:can\s+be|is)\s+used\s+for|is\s+for)\s+(.+?)[?.!\s]*$/i;
|
|
4504
4511
|
// Widened 2026-07-11 (live-caught follow-up to the ambiguousParse fix, commit
|
|
4505
4512
|
// 5c858bf): on the FIRST turn of a graph-less session, dispatchTool's
|
|
4506
4513
|
// loadGraph() throws its own documented "the graph is empty... this repo
|
|
@@ -4548,6 +4555,32 @@ async function factAnswer(memoryDir, query, envelope, miss, biasByBundle = {}) {
|
|
|
4548
4555
|
try { ({ normFactTerm } = await import("./memory/core.mjs")); } catch { return null; }
|
|
4549
4556
|
const q = String(query).trim();
|
|
4550
4557
|
|
|
4558
|
+
// (a-pre) "what is used for riding" / "what can be used for riding" / "what
|
|
4559
|
+
// is for riding" — the reverse-by-OBJECT mirror of BUG 1's forward reader
|
|
4560
|
+
// ("what is a tree used for", the (a) block just below). Checked BEFORE (a)
|
|
4561
|
+
// deliberately: this phrasing's leading "what is …" ALSO matches (a)'s own
|
|
4562
|
+
// BARE_WHATIS_RE, which would otherwise greedily treat "used for riding" as
|
|
4563
|
+
// one literal term to define — a guaranteed miss, since no vocabulary term
|
|
4564
|
+
// is ever named "used for riding" — and (a) always returns (hit, honest
|
|
4565
|
+
// per-relation "no", or null), never falling through to a later reader. Only
|
|
4566
|
+
// takes over when it finds a REAL hit; a non-match or zero-hit case falls
|
|
4567
|
+
// through unchanged to (a) and beyond, so ordinary miss messaging is
|
|
4568
|
+
// untouched. mgx:usedFor instead of mgx:hasA; same filter/rank/render/
|
|
4569
|
+
// paginate recipe as (b4)'s WHAT_HAS_RE below.
|
|
4570
|
+
const usedForQ = q.match(WHAT_USED_FOR_RE);
|
|
4571
|
+
if (usedForQ) {
|
|
4572
|
+
const variants = factTermVariants(normFactTerm, usedForQ[1]);
|
|
4573
|
+
const hits = (await factRows(memoryDir)).filter((f) => f.predicate === "mgx:usedFor" && variants.has(f.object));
|
|
4574
|
+
if (hits.length) {
|
|
4575
|
+
const ranked = rankByBiasThenTrust(uniqueFacts(hits), biasByBundle);
|
|
4576
|
+
const lines = ranked.map(renderFactLine);
|
|
4577
|
+
const shown = lines.slice(0, FACT_ANSWER_CAP);
|
|
4578
|
+
const rest = lines.slice(FACT_ANSWER_CAP);
|
|
4579
|
+
const extra = rest.length ? `\n…and ${rest.length} more — say 'more' to see them.` : "";
|
|
4580
|
+
return { text: shown.join("\n") + extra, replace: true, ...(rest.length ? { pending: { items: rest, noun: "facts" } } : {}) };
|
|
4581
|
+
}
|
|
4582
|
+
}
|
|
4583
|
+
|
|
4551
4584
|
// (a) meta-shaped questions ("what is a module", "what does cache mean") — the
|
|
4552
4585
|
// parsed object term, matched against fact SUBJECTS; consulted for hits (append
|
|
4553
4586
|
// alongside the schema-docs answer) and misses (facts answer alone) alike.
|