@polycode-projects/the-mechanical-code-talker 1.10.3 → 1.10.4

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/chat.mjs +19 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polycode-projects/the-mechanical-code-talker",
3
- "version": "1.10.3",
3
+ "version": "1.10.4",
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/chat.mjs CHANGED
@@ -4121,15 +4121,16 @@ const KNOW_ABOUT_RE = /^(?:what\s+do\s+you\s+know\s+about|what(?:'s|s|\s+is)\s+i
4121
4121
  /** How many facts a single answer lists before the remainder is paged with "more". */
4122
4122
  const FACT_ANSWER_CAP = 32;
4123
4123
 
4124
- /** Four sibling readers closing the gap left
4124
+ /** Five sibling readers closing the gap left
4125
4125
  * by ISA_ASK_RE's own family: forward yes/no and reverse-by-object shapes for
4126
4126
  * `mgx:capableOf`, `mgx:hasA`, and the ISA-family predicates. None of these
4127
- * four leads ("can"/"could", "what can … do", "what has", "what inherit(s)")
4127
+ * five leads ("can"/"could", "does/do … have", "what can … do", "what has", "what inherit(s)")
4128
4128
  * overlaps KNOW_ABOUT_RE's fixed leads above, or RELATION_FACT_YESNO_RE/
4129
4129
  * RELATION_WHO_ASK_RE's required leading "is/are/was/were" (those two live in
4130
4130
  * the separate factReadBack, only ever reached via `factAnswer(...) ??
4131
4131
  * factReadBack(...)` — never both). */
4132
4132
  const CAN_ASK_RE = /^(?:can|could)\s+(?:an?\s+)?([\w'-]+(?:\s+[\w'-]+)*?)\s+([a-z]+)[?.!\s]*$/i;
4133
+ const DOES_HAVE_ASK_RE = /^(?:does|do)\s+(?:an?\s+|the\s+)?(.+?)\s+have\s+(?:an?\s+|the\s+)?(.+?)[?.!\s]*$/i;
4133
4134
  const WHAT_CAN_DO_RE = /^what\s+can\s+(?:an?\s+)?(.+?)\s+do[?.!\s]*$/i;
4134
4135
  const WHAT_HAS_RE = /^what\s+has\s+(?:an?\s+)?(.+?)[?.!\s]*$/i;
4135
4136
  // "what is used for riding" / "what can be used for riding" / "what is for
@@ -4349,6 +4350,22 @@ export async function factAnswer(memoryDir, query, envelope, miss, biasByBundle
4349
4350
  return null;
4350
4351
  }
4351
4352
 
4353
+ // (b2b) "does a dog have a tail" — yes iff a remembered mgx:hasA fact says
4354
+ // so: the forward yes/no mirror of WHAT_HAS_RE below, with the same
4355
+ // single-hit lookup and "never a guessed no" discipline as CAN_ASK_RE
4356
+ // above. Only diverts on a REAL hit, so a code-shaped "does app.mjs have
4357
+ // tests" (no hasA fact) keeps whatever miss text already stands.
4358
+ const doesHave = q.match(DOES_HAVE_ASK_RE);
4359
+ if (doesHave) {
4360
+ const subj = factTermVariants(normFactTerm, doesHave[1]);
4361
+ const obj = factTermVariants(normFactTerm, doesHave[2]);
4362
+ const hit = (await memoryFacts(memoryDir)).find(
4363
+ (f) => f.predicate === "mgx:hasA" && subj.has(f.subject) && obj.has(f.object),
4364
+ );
4365
+ if (hit) return { text: `yes — ${renderFactLine(hit)}`, replace: true };
4366
+ return null;
4367
+ }
4368
+
4352
4369
  // (b3) "what can a dog do" — every remembered mgx:capableOf fact for the
4353
4370
  // subject, open-list. Reuses the meta-lane's subject-hits/rank/render/
4354
4371
  // paginate recipe (lane (a) above) verbatim, with the predicate hardcoded.