@geometra/mcp 1.45.0 → 1.46.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.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,52 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { valuesEquivalent } from '../server.js';
3
+ describe('valuesEquivalent', () => {
4
+ describe('plain strings', () => {
5
+ it('matches identical strings case-insensitively', () => {
6
+ expect(valuesEquivalent('Charlie', 'charlie')).toBe(true);
7
+ });
8
+ it('matches with whitespace collapse', () => {
9
+ expect(valuesEquivalent('Charlie Greenman', 'Charlie Greenman')).toBe(true);
10
+ });
11
+ it('rejects unrelated strings', () => {
12
+ expect(valuesEquivalent('Charlie', 'Alice')).toBe(false);
13
+ });
14
+ });
15
+ describe('phone numbers', () => {
16
+ it('matches identical phone signatures', () => {
17
+ expect(valuesEquivalent('9296081737', '9296081737')).toBe(true);
18
+ });
19
+ // Bug surfaced by JobForge round-2 marathon — Cloudflare FDE NYC #312.
20
+ // Greenhouse formats `+1-929-608-1737` → `(929) 608-1737`. The expected
21
+ // side carries the country code; the actual readback drops it. The
22
+ // strict-equality digit comparison previously rejected this as a
23
+ // mismatch even though the underlying value is correct.
24
+ it('matches phone numbers when expected has country code and actual does not', () => {
25
+ expect(valuesEquivalent('+1-929-608-1737', '(929) 608-1737')).toBe(true);
26
+ });
27
+ it('matches phone numbers when actual has country code and expected does not', () => {
28
+ expect(valuesEquivalent('(929) 608-1737', '+1-929-608-1737')).toBe(true);
29
+ });
30
+ it('matches across many ATS auto-format variants', () => {
31
+ const expected = '+19296081737';
32
+ expect(valuesEquivalent(expected, '(929) 608-1737')).toBe(true);
33
+ expect(valuesEquivalent(expected, '929-608-1737')).toBe(true);
34
+ expect(valuesEquivalent(expected, '929.608.1737')).toBe(true);
35
+ expect(valuesEquivalent(expected, '929 608 1737')).toBe(true);
36
+ expect(valuesEquivalent(expected, '+1 (929) 608-1737')).toBe(true);
37
+ });
38
+ it('rejects two phone numbers that differ in the local 10 digits', () => {
39
+ expect(valuesEquivalent('+1-929-608-1737', '(415) 555-0123')).toBe(false);
40
+ });
41
+ it('rejects suffix-match below the 7-digit local minimum', () => {
42
+ // Pure 6-digit IDs must not match against a longer phone signature
43
+ // even if the IDs happen to be a digit-suffix.
44
+ expect(valuesEquivalent('19296081737', '081737')).toBe(false);
45
+ });
46
+ });
47
+ describe('formatted numbers', () => {
48
+ it('matches a salary across comma formatting', () => {
49
+ expect(valuesEquivalent('$160000', '$160,000')).toBe(true);
50
+ });
51
+ });
52
+ });
package/dist/server.d.ts CHANGED
@@ -21,5 +21,6 @@ interface NodeFilter {
21
21
  busy?: boolean;
22
22
  }
23
23
  export declare function createServer(): McpServer;
24
+ export declare function valuesEquivalent(expected: string, actual: string): boolean;
24
25
  export declare function findNodes(node: A11yNode, filter: NodeFilter): A11yNode[];
25
26
  export {};
package/dist/server.js CHANGED
@@ -2600,7 +2600,26 @@ function fieldStatePayload(session, fieldLabel) {
2600
2600
  };
2601
2601
  }
2602
2602
  function waitStatusPayload(wait) {
2603
- return wait ? { wait: wait.status } : {};
2603
+ if (!wait)
2604
+ return {};
2605
+ const payload = { wait: wait.status };
2606
+ // Surface navigation info from proxy click handlers so callers can tell
2607
+ // when a click triggered a full-page nav (form submit → thank-you page).
2608
+ // Without this, the proxy session may die on the next request and the
2609
+ // caller would see session_not_found with no clue WHY. Bug surfaced by
2610
+ // JobForge round-2 marathon — Cloudflare FDE NYC #312 and Airtable PM
2611
+ // AI #94 both had Submit-clicks that navigated and tore down the proxy.
2612
+ if (wait.result && typeof wait.result === 'object') {
2613
+ const result = wait.result;
2614
+ if (result.navigated === true) {
2615
+ payload.navigated = true;
2616
+ if (typeof result.pageUrl === 'string')
2617
+ payload.pageUrl = result.pageUrl;
2618
+ if (typeof result.urlBefore === 'string')
2619
+ payload.urlBefore = result.urlBefore;
2620
+ }
2621
+ }
2622
+ return payload;
2604
2623
  }
2605
2624
  function compactFilterPayload(filter) {
2606
2625
  return Object.fromEntries(Object.entries(filter).filter(([, value]) => value !== undefined));
@@ -3582,12 +3601,32 @@ function looksLikeFormattedNumber(value) {
3582
3601
  function digitSignature(value) {
3583
3602
  return value.replace(/\D+/g, '');
3584
3603
  }
3585
- function valuesEquivalent(expected, actual) {
3604
+ export function valuesEquivalent(expected, actual) {
3586
3605
  if (expected.toLowerCase() === actual.toLowerCase())
3587
3606
  return true;
3588
- // Both look like phones → compare digit signatures only
3607
+ // Both look like phones → compare digit signatures, but allow one to be
3608
+ // a suffix of the other so that an explicit country code on the expected
3609
+ // side ("+1-929-608-1737" → digits "19296081737") still matches an ATS
3610
+ // readback that omits it ("(929) 608-1737" → digits "9296081737"). The
3611
+ // suffix check is direction-agnostic — either side may carry the country
3612
+ // code. Without this, Greenhouse/Workday/Lever auto-formatted phone
3613
+ // fields false-flag as mismatched even though the value is correct.
3614
+ // Bug surfaced by JobForge round-2 marathon — Cloudflare FDE NYC #312.
3589
3615
  if (looksLikePhoneNumber(expected) && looksLikePhoneNumber(actual)) {
3590
- return digitSignature(expected) === digitSignature(actual);
3616
+ const eDigits = digitSignature(expected);
3617
+ const aDigits = digitSignature(actual);
3618
+ if (!eDigits || !aDigits)
3619
+ return false;
3620
+ if (eDigits === aDigits)
3621
+ return true;
3622
+ // Suffix tolerance for country-code drift — only accept if the longer
3623
+ // signature ends with the shorter, AND the shorter is at least 7 digits
3624
+ // (NANP local minimum) so we don't false-match on tiny extension ids.
3625
+ const longer = eDigits.length >= aDigits.length ? eDigits : aDigits;
3626
+ const shorter = eDigits.length >= aDigits.length ? aDigits : eDigits;
3627
+ if (shorter.length >= 7 && longer.endsWith(shorter))
3628
+ return true;
3629
+ return false;
3591
3630
  }
3592
3631
  // Both look like formatted numbers → compare digit signatures only
3593
3632
  if (looksLikeFormattedNumber(expected) || looksLikeFormattedNumber(actual)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geometra/mcp",
3
- "version": "1.45.0",
3
+ "version": "1.46.0",
4
4
  "description": "MCP server for Geometra — interact with running Geometra apps via the geometry protocol, no browser needed",
5
5
  "license": "MIT",
6
6
  "type": "module",