@geometra/mcp 1.63.2 → 1.65.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/dist/session.d.ts CHANGED
@@ -29,10 +29,29 @@ export interface A11yNode {
29
29
  scrollX?: number;
30
30
  scrollY?: number;
31
31
  controlTag?: string;
32
+ /** Stable authored DOM identity emitted by the proxy extractor (`id:` or `name:`). */
33
+ controlKey?: string;
34
+ controlId?: string;
35
+ controlName?: string;
36
+ options?: Array<{
37
+ value: string;
38
+ label: string;
39
+ disabled: boolean;
40
+ selected: boolean;
41
+ index: number;
42
+ }>;
32
43
  placeholder?: string;
33
44
  inputPattern?: string;
34
45
  inputType?: string;
35
46
  autocomplete?: string;
47
+ /** True when this semantic node represents an `<input type="file">`. */
48
+ fileInput?: boolean;
49
+ /** Authored file-type filter from the input's `accept` attribute. */
50
+ accept?: string;
51
+ /** True when the file input accepts more than one file. */
52
+ multiple?: boolean;
53
+ /** Geometry-only fallback that cannot be resolved by semantic proxy actions. */
54
+ coordinateOnly?: boolean;
36
55
  /**
37
56
  * True when the extractor detected that this `<input>` (or role=textbox)
38
57
  * lives inside an autocomplete / searchable combobox wrapper — React
@@ -281,11 +300,22 @@ export interface PageSectionDetail {
281
300
  items: PageListItemModel[];
282
301
  textPreview: string[];
283
302
  }
284
- export type FormSchemaFieldKind = 'text' | 'choice' | 'toggle' | 'multi_choice';
303
+ export type FormSchemaFieldKind = 'text' | 'choice' | 'toggle' | 'multi_choice' | 'file';
285
304
  export type FormSchemaChoiceType = 'select' | 'group' | 'listbox';
286
305
  export type FormSchemaContextMode = 'auto' | 'always' | 'none';
306
+ export interface FormSchemaOption {
307
+ /** Stable within the authored control identity; index disambiguates duplicate values/labels. */
308
+ id: string;
309
+ value: string;
310
+ label: string;
311
+ index: number;
312
+ disabled?: boolean;
313
+ selected?: boolean;
314
+ }
287
315
  export interface FormSchemaField {
288
316
  id: string;
317
+ /** Authored DOM identity used for exact proxy-side resolution before accessible-label fallback. */
318
+ fieldKey?: string;
289
319
  kind: FormSchemaFieldKind;
290
320
  label: string;
291
321
  required?: boolean;
@@ -299,12 +329,15 @@ export interface FormSchemaField {
299
329
  values?: string[];
300
330
  optionCount?: number;
301
331
  options?: string[];
332
+ optionDetails?: FormSchemaOption[];
302
333
  aliases?: Record<string, string[]>;
303
334
  format?: {
304
335
  placeholder?: string;
305
336
  pattern?: string;
306
337
  inputType?: string;
307
338
  autocomplete?: string;
339
+ accept?: string;
340
+ multiple?: boolean;
308
341
  };
309
342
  context?: NodeContextModel;
310
343
  }
@@ -346,6 +379,60 @@ export interface FormSchemaBuildOptions {
346
379
  includeOptions?: boolean;
347
380
  includeContext?: FormSchemaContextMode;
348
381
  }
382
+ export interface FormGraphSource {
383
+ id: string;
384
+ kind: 'html';
385
+ title?: string;
386
+ url?: string;
387
+ }
388
+ export interface FormGraphSourceAnchor {
389
+ sourceId: string;
390
+ kind: 'html';
391
+ fieldName?: string;
392
+ pointer?: string;
393
+ }
394
+ export interface FormGraphField {
395
+ id: string;
396
+ path: string;
397
+ label: string;
398
+ kind: 'boolean' | 'enum' | 'text' | 'textarea' | 'email' | 'phone' | 'date' | 'number';
399
+ required?: boolean;
400
+ reviewRequired?: boolean;
401
+ aliases?: string[];
402
+ options?: Array<{
403
+ value: string;
404
+ label: string;
405
+ }>;
406
+ constraints?: {
407
+ pattern?: string;
408
+ };
409
+ sourceAnchors?: FormGraphSourceAnchor[];
410
+ metadata?: Record<string, unknown>;
411
+ }
412
+ export interface FormGraphModel {
413
+ formgraph: '0.1';
414
+ id: string;
415
+ title: string;
416
+ description?: string;
417
+ sources: FormGraphSource[];
418
+ fields: FormGraphField[];
419
+ evidence: [];
420
+ dependencies: [];
421
+ review: {
422
+ autoSubmitAllowed: false;
423
+ requiredBeforeSubmit: true;
424
+ };
425
+ metadata: {
426
+ producer: 'geometra';
427
+ geometra: {
428
+ formId: string;
429
+ fieldCount: number;
430
+ requiredCount: number;
431
+ invalidCount: number;
432
+ sections?: FormSchemaSection[];
433
+ };
434
+ };
435
+ }
349
436
  export interface UiNodeUpdate {
350
437
  before: CompactUiNode;
351
438
  after: CompactUiNode;
@@ -389,7 +476,11 @@ export interface WorkflowPageEntry {
389
476
  pageUrl: string;
390
477
  formId?: string;
391
478
  formName?: string;
392
- filledValues: Record<string, string | boolean>;
479
+ /** Backward-compatible value map whose contents are always redaction markers. */
480
+ filledValues: Record<string, '[REDACTED]'>;
481
+ /** Stable field identities retained without submitted values. */
482
+ filledFields: string[];
483
+ valuesRedacted: true;
393
484
  filledAt: number;
394
485
  fieldCount: number;
395
486
  invalidCount: number;
@@ -405,7 +496,28 @@ export interface Session {
405
496
  layout: Record<string, unknown> | null;
406
497
  tree: Record<string, unknown> | null;
407
498
  url: string;
499
+ /** Private bearer capability for an authenticated proxy transport. */
500
+ transportAuthToken?: string;
408
501
  updateRevision: number;
502
+ /** Negotiated owner of the WebSocket endpoint. */
503
+ peerTransport?: 'native' | 'proxy';
504
+ /** Negotiated shared geometry protocol version. */
505
+ peerGeometryProtocolVersion?: number;
506
+ /** Negotiated browser-only action protocol version. */
507
+ peerProxyActionProtocolVersion?: number;
508
+ /** True when the peer advertised the split protocol contract explicitly. */
509
+ peerAdvertisedSplitProtocol?: boolean;
510
+ peerProtocolCapabilities?: {
511
+ authenticatedController?: boolean;
512
+ requestScopedAcks?: boolean;
513
+ actionDeadlines?: boolean;
514
+ idempotentRequestIds?: boolean;
515
+ atomicTypeText?: boolean;
516
+ proxyActions?: boolean;
517
+ exactFieldIdentity?: boolean;
518
+ verifiedFileUploads?: boolean;
519
+ binaryFraming?: boolean;
520
+ };
409
521
  /** Present when this session owns a child geometra-proxy process (pageUrl connect). */
410
522
  proxyChild?: ChildProcess;
411
523
  proxyRuntime?: EmbeddedProxyRuntime;
@@ -426,6 +538,10 @@ export interface Session {
426
538
  revision: number;
427
539
  forms: FormSchemaModel[];
428
540
  }>;
541
+ /** True only after the current WebSocket transport has supplied a full frame. */
542
+ hasFreshFrame?: boolean;
543
+ /** Permanently set when this session has been disconnected or otherwise retired. */
544
+ disposed?: boolean;
429
545
  workflowState?: WorkflowState;
430
546
  reconnectInFlight?: Promise<boolean>;
431
547
  lifecycleTaskId?: string;
@@ -436,6 +552,10 @@ export interface Session {
436
552
  heartbeatInterval?: ReturnType<typeof setInterval> | null;
437
553
  heartbeatLastMessageAt?: number;
438
554
  heartbeatPendingPongBy?: number | null;
555
+ /** Mutating operations whose caller timed out before a terminal response. */
556
+ ambiguousOperations?: Map<string, AmbiguousOperation>;
557
+ /** Mutating operations currently awaiting a terminal response. */
558
+ inFlightMutations?: Map<string, AmbiguousOperation>;
439
559
  }
440
560
  export interface SessionConnectTrace {
441
561
  mode: 'direct-ws' | 'fresh-proxy' | 'reused-proxy';
@@ -455,17 +575,53 @@ export interface SessionConnectTrace {
455
575
  export interface UpdateWaitResult {
456
576
  status: 'updated' | 'acknowledged' | 'timed_out';
457
577
  timeoutMs: number;
578
+ /** Wire identity used to correlate the terminal proxy response. */
579
+ requestId: string;
580
+ /** Stable logical identity shared by every wire phase of one action. */
581
+ actionId: string;
458
582
  result?: unknown;
459
583
  }
584
+ interface AmbiguousOperation {
585
+ fingerprint: string;
586
+ actionId: string;
587
+ requestId: string;
588
+ requestIds: string[];
589
+ wireMessages: string[];
590
+ actionTimeoutMs?: number;
591
+ timeoutMs: number;
592
+ idempotent: boolean;
593
+ mutating: boolean;
594
+ /** A correlated ACK alone is insufficient for actions such as navigation. */
595
+ requireUpdateOnAck?: boolean;
596
+ /** Protocol floor that the terminal ACK must explicitly satisfy. */
597
+ requiredProtocolVersion?: number;
598
+ /** Any non-deduplication phase error permanently blocks later ACK promotion. */
599
+ stickyError?: Error;
600
+ /**
601
+ * Once any caller observes a timeout, identical intent is permanently
602
+ * pinned to this identity for the rest of the session. A future caller
603
+ * cannot prove it is (or is not) the timed-out caller.
604
+ */
605
+ permanentTombstone?: boolean;
606
+ completion?: {
607
+ kind: 'result';
608
+ value: UpdateWaitResult;
609
+ } | {
610
+ kind: 'error';
611
+ error: Error;
612
+ };
613
+ }
460
614
  export type ProxyFillField = {
461
615
  kind: 'auto';
462
616
  fieldId?: string;
617
+ fieldKey?: string;
463
618
  fieldLabel: string;
464
619
  value: string | boolean;
465
620
  exact?: boolean;
466
621
  } | {
467
622
  kind: 'text';
468
623
  fieldId?: string;
624
+ fieldKey?: string;
469
625
  fieldLabel: string;
470
626
  value: string;
471
627
  exact?: boolean;
@@ -474,13 +630,17 @@ export type ProxyFillField = {
474
630
  } | {
475
631
  kind: 'choice';
476
632
  fieldId?: string;
633
+ fieldKey?: string;
477
634
  fieldLabel: string;
478
635
  value: string;
636
+ optionIndex?: number;
479
637
  query?: string;
480
638
  exact?: boolean;
481
639
  choiceType?: FormSchemaChoiceType;
482
640
  } | {
483
641
  kind: 'toggle';
642
+ fieldId?: string;
643
+ fieldKey?: string;
484
644
  label: string;
485
645
  checked?: boolean;
486
646
  exact?: boolean;
@@ -488,6 +648,7 @@ export type ProxyFillField = {
488
648
  } | {
489
649
  kind: 'file';
490
650
  fieldId?: string;
651
+ fieldKey?: string;
491
652
  fieldLabel: string;
492
653
  paths: string[];
493
654
  exact?: boolean;
@@ -522,6 +683,8 @@ export declare function connect(url: string, opts?: {
522
683
  skipInitialResize?: boolean;
523
684
  closePreviousProxy?: boolean;
524
685
  awaitInitialFrame?: boolean;
686
+ authToken?: string;
687
+ isolated?: boolean;
525
688
  }): Promise<Session>;
526
689
  /**
527
690
  * Start geometra-proxy for `pageUrl`, connect to its WebSocket, and attach the child
@@ -538,12 +701,10 @@ export declare function connectThroughProxy(options: {
538
701
  awaitInitialFrame?: boolean;
539
702
  eagerInitialExtract?: boolean;
540
703
  /**
541
- * When true, bypass the reusable proxy pool entirely and always spawn a
542
- * fresh Chromium for this session. The session is tagged isolated, never
543
- * entered into the pool on disconnect, and its underlying browser is
544
- * destroyed when the session disconnects. Use for parallel form
545
- * submission so localStorage / cookies / page state from one job cannot
546
- * leak into another. Default false preserves the existing pool behavior.
704
+ * Browser sessions are isolated by default. Pass `false` explicitly to
705
+ * opt into sequential warm-browser reuse, including shared cookies and
706
+ * localStorage. Isolated sessions never enter the reusable pool and their
707
+ * browser is destroyed on disconnect.
547
708
  */
548
709
  isolated?: boolean;
549
710
  /**
@@ -598,7 +759,10 @@ export declare function disconnect(opts?: {
598
759
  closeProxy?: boolean;
599
760
  sessionId?: string;
600
761
  }): void;
762
+ /** Process/test teardown only. User-facing disconnects are always owner-scoped. */
763
+ export declare function shutdownAllSessionsAndProxies(): void;
601
764
  export declare function waitForUiCondition(session: Session, predicate: () => boolean, timeoutMs: number): Promise<boolean>;
765
+ export declare function ensureSessionConnected(session: Session): Promise<void>;
602
766
  /**
603
767
  * Send a click event at (x, y) and wait for the next frame/patch response.
604
768
  */
@@ -618,13 +782,17 @@ export declare function sendKey(session: Session, key: string, modifiers?: {
618
782
  }, timeoutMs?: number): Promise<UpdateWaitResult>;
619
783
  /**
620
784
  * Attach local file(s). Paths must exist on the machine running `@geometra/proxy` (not the MCP host).
621
- * Optional `x`,`y` click opens a file chooser; omit to use the first `input[type=file]` in any frame.
785
+ * Optional `x`,`y` click opens a file chooser. Callers must provide an explicit
786
+ * coordinate or semantic target; MCP never intentionally requests a global
787
+ * first-file-input fallback.
622
788
  */
623
789
  export declare function sendFileUpload(session: Session, paths: string[], opts?: {
624
790
  click?: {
625
791
  x: number;
626
792
  y: number;
627
793
  };
794
+ fieldId?: string;
795
+ fieldKey?: string;
628
796
  fieldLabel?: string;
629
797
  exact?: boolean;
630
798
  strategy?: 'auto' | 'chooser' | 'hidden' | 'drop';
@@ -632,11 +800,14 @@ export declare function sendFileUpload(session: Session, paths: string[], opts?:
632
800
  x: number;
633
801
  y: number;
634
802
  };
803
+ contextText?: string;
804
+ sectionText?: string;
635
805
  }, timeoutMs?: number): Promise<UpdateWaitResult>;
636
806
  /** Set a labeled text-like field (`input`, `textarea`, contenteditable, ARIA textbox) semantically. */
637
807
  export declare function sendFieldText(session: Session, fieldLabel: string, value: string, opts?: {
638
808
  exact?: boolean;
639
809
  fieldId?: string;
810
+ fieldKey?: string;
640
811
  typingDelayMs?: number;
641
812
  imeFriendly?: boolean;
642
813
  }, timeoutMs?: number): Promise<UpdateWaitResult>;
@@ -646,6 +817,8 @@ export declare function sendFieldChoice(session: Session, fieldLabel: string, va
646
817
  query?: string;
647
818
  choiceType?: FormSchemaChoiceType;
648
819
  fieldId?: string;
820
+ fieldKey?: string;
821
+ optionIndex?: number;
649
822
  }, timeoutMs?: number): Promise<UpdateWaitResult>;
650
823
  /** Fill several semantic form fields in one proxy-side batch. */
651
824
  export declare function sendFillFields(session: Session, fields: ProxyFillField[], timeoutMs?: number): Promise<UpdateWaitResult>;
@@ -662,12 +835,10 @@ export declare function sendFillOtp(session: Session, value: string, opts?: {
662
835
  /** ARIA `role=option` listbox (e.g. React Select). Optional click opens the list. */
663
836
  export declare function sendListboxPick(session: Session, label: string, opts?: {
664
837
  exact?: boolean;
665
- open?: {
666
- x: number;
667
- y: number;
668
- };
669
838
  fieldLabel?: string;
670
839
  query?: string;
840
+ fieldId?: string;
841
+ fieldKey?: string;
671
842
  }, timeoutMs?: number): Promise<UpdateWaitResult>;
672
843
  /** Native `<select>` only: click the control center, then pick by value, label text, or zero-based index. */
673
844
  export declare function sendSelectOption(session: Session, x: number, y: number, option: {
@@ -680,6 +851,9 @@ export declare function sendSetChecked(session: Session, label: string, opts?: {
680
851
  checked?: boolean;
681
852
  exact?: boolean;
682
853
  controlType?: 'checkbox' | 'radio';
854
+ fieldKey?: string;
855
+ contextText?: string;
856
+ sectionText?: string;
683
857
  }, timeoutMs?: number): Promise<UpdateWaitResult>;
684
858
  /** Mouse wheel / scroll. Optional `x`,`y` move pointer before scrolling. */
685
859
  export declare function sendWheel(session: Session, deltaY: number, opts?: {
@@ -732,6 +906,8 @@ export declare function buildPageModel(root: A11yNode, options?: {
732
906
  blockDetection?: boolean;
733
907
  }): PageModel;
734
908
  export declare function buildFormSchemas(root: A11yNode, options?: FormSchemaBuildOptions): FormSchemaModel[];
909
+ export declare function buildFormGraphs(root: A11yNode, options?: FormSchemaBuildOptions): FormGraphModel[];
910
+ export declare function formSchemaToFormGraph(schema: FormSchemaModel, pageUrl?: string): FormGraphModel;
735
911
  /**
736
912
  * Required-field snapshot for automation: every required field in a form, including
737
913
  * offscreen entries, annotated with visibility and scroll hints so agents do not