@ticktockbent/charlotte 0.1.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.
Files changed (136) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +254 -0
  4. package/dist/browser/browser-manager.d.ts +14 -0
  5. package/dist/browser/browser-manager.d.ts.map +1 -0
  6. package/dist/browser/browser-manager.js +72 -0
  7. package/dist/browser/browser-manager.js.map +1 -0
  8. package/dist/browser/cdp-session.d.ts +7 -0
  9. package/dist/browser/cdp-session.d.ts.map +1 -0
  10. package/dist/browser/cdp-session.js +35 -0
  11. package/dist/browser/cdp-session.js.map +1 -0
  12. package/dist/browser/page-manager.d.ts +30 -0
  13. package/dist/browser/page-manager.d.ts.map +1 -0
  14. package/dist/browser/page-manager.js +123 -0
  15. package/dist/browser/page-manager.js.map +1 -0
  16. package/dist/dev/auditor.d.ts +39 -0
  17. package/dist/dev/auditor.d.ts.map +1 -0
  18. package/dist/dev/auditor.js +474 -0
  19. package/dist/dev/auditor.js.map +1 -0
  20. package/dist/dev/dev-mode-state.d.ts +24 -0
  21. package/dist/dev/dev-mode-state.d.ts.map +1 -0
  22. package/dist/dev/dev-mode-state.js +93 -0
  23. package/dist/dev/dev-mode-state.js.map +1 -0
  24. package/dist/dev/file-watcher.d.ts +20 -0
  25. package/dist/dev/file-watcher.d.ts.map +1 -0
  26. package/dist/dev/file-watcher.js +78 -0
  27. package/dist/dev/file-watcher.js.map +1 -0
  28. package/dist/dev/static-server.d.ts +18 -0
  29. package/dist/dev/static-server.d.ts.map +1 -0
  30. package/dist/dev/static-server.js +73 -0
  31. package/dist/dev/static-server.js.map +1 -0
  32. package/dist/index.d.ts +3 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +60 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/renderer/accessibility-extractor.d.ts +19 -0
  37. package/dist/renderer/accessibility-extractor.d.ts.map +1 -0
  38. package/dist/renderer/accessibility-extractor.js +138 -0
  39. package/dist/renderer/accessibility-extractor.js.map +1 -0
  40. package/dist/renderer/content-extractor.d.ts +6 -0
  41. package/dist/renderer/content-extractor.d.ts.map +1 -0
  42. package/dist/renderer/content-extractor.js +150 -0
  43. package/dist/renderer/content-extractor.js.map +1 -0
  44. package/dist/renderer/dom-path.d.ts +4 -0
  45. package/dist/renderer/dom-path.d.ts.map +1 -0
  46. package/dist/renderer/dom-path.js +34 -0
  47. package/dist/renderer/dom-path.js.map +1 -0
  48. package/dist/renderer/element-id-generator.d.ts +19 -0
  49. package/dist/renderer/element-id-generator.d.ts.map +1 -0
  50. package/dist/renderer/element-id-generator.js +73 -0
  51. package/dist/renderer/element-id-generator.js.map +1 -0
  52. package/dist/renderer/interactive-extractor.d.ts +13 -0
  53. package/dist/renderer/interactive-extractor.d.ts.map +1 -0
  54. package/dist/renderer/interactive-extractor.js +161 -0
  55. package/dist/renderer/interactive-extractor.js.map +1 -0
  56. package/dist/renderer/layout-extractor.d.ts +8 -0
  57. package/dist/renderer/layout-extractor.d.ts.map +1 -0
  58. package/dist/renderer/layout-extractor.js +48 -0
  59. package/dist/renderer/layout-extractor.js.map +1 -0
  60. package/dist/renderer/renderer-pipeline.d.ts +26 -0
  61. package/dist/renderer/renderer-pipeline.d.ts.map +1 -0
  62. package/dist/renderer/renderer-pipeline.js +163 -0
  63. package/dist/renderer/renderer-pipeline.js.map +1 -0
  64. package/dist/server.d.ts +19 -0
  65. package/dist/server.d.ts.map +1 -0
  66. package/dist/server.js +39 -0
  67. package/dist/server.js.map +1 -0
  68. package/dist/state/differ.d.ts +9 -0
  69. package/dist/state/differ.d.ts.map +1 -0
  70. package/dist/state/differ.js +295 -0
  71. package/dist/state/differ.js.map +1 -0
  72. package/dist/state/snapshot-store.d.ts +52 -0
  73. package/dist/state/snapshot-store.d.ts.map +1 -0
  74. package/dist/state/snapshot-store.js +98 -0
  75. package/dist/state/snapshot-store.js.map +1 -0
  76. package/dist/tools/dev-mode.d.ts +4 -0
  77. package/dist/tools/dev-mode.d.ts.map +1 -0
  78. package/dist/tools/dev-mode.js +160 -0
  79. package/dist/tools/dev-mode.js.map +1 -0
  80. package/dist/tools/evaluate.d.ts +10 -0
  81. package/dist/tools/evaluate.d.ts.map +1 -0
  82. package/dist/tools/evaluate.js +109 -0
  83. package/dist/tools/evaluate.js.map +1 -0
  84. package/dist/tools/interaction.d.ts +4 -0
  85. package/dist/tools/interaction.d.ts.map +1 -0
  86. package/dist/tools/interaction.js +680 -0
  87. package/dist/tools/interaction.js.map +1 -0
  88. package/dist/tools/navigation.d.ts +4 -0
  89. package/dist/tools/navigation.d.ts.map +1 -0
  90. package/dist/tools/navigation.js +136 -0
  91. package/dist/tools/navigation.js.map +1 -0
  92. package/dist/tools/observation.d.ts +4 -0
  93. package/dist/tools/observation.d.ts.map +1 -0
  94. package/dist/tools/observation.js +278 -0
  95. package/dist/tools/observation.js.map +1 -0
  96. package/dist/tools/session.d.ts +4 -0
  97. package/dist/tools/session.d.ts.map +1 -0
  98. package/dist/tools/session.js +372 -0
  99. package/dist/tools/session.js.map +1 -0
  100. package/dist/tools/tool-helpers.d.ts +89 -0
  101. package/dist/tools/tool-helpers.d.ts.map +1 -0
  102. package/dist/tools/tool-helpers.js +127 -0
  103. package/dist/tools/tool-helpers.js.map +1 -0
  104. package/dist/types/config.d.ts +7 -0
  105. package/dist/types/config.d.ts.map +1 -0
  106. package/dist/types/config.js +7 -0
  107. package/dist/types/config.js.map +1 -0
  108. package/dist/types/element-id.d.ts +8 -0
  109. package/dist/types/element-id.d.ts.map +1 -0
  110. package/dist/types/element-id.js +19 -0
  111. package/dist/types/element-id.js.map +1 -0
  112. package/dist/types/errors.d.ts +22 -0
  113. package/dist/types/errors.d.ts.map +1 -0
  114. package/dist/types/errors.js +30 -0
  115. package/dist/types/errors.js.map +1 -0
  116. package/dist/types/page-representation.d.ts +84 -0
  117. package/dist/types/page-representation.d.ts.map +1 -0
  118. package/dist/types/page-representation.js +2 -0
  119. package/dist/types/page-representation.js.map +1 -0
  120. package/dist/types/snapshot.d.ts +22 -0
  121. package/dist/types/snapshot.d.ts.map +1 -0
  122. package/dist/types/snapshot.js +2 -0
  123. package/dist/types/snapshot.js.map +1 -0
  124. package/dist/utils/hash.d.ts +2 -0
  125. package/dist/utils/hash.d.ts.map +1 -0
  126. package/dist/utils/hash.js +6 -0
  127. package/dist/utils/hash.js.map +1 -0
  128. package/dist/utils/logger.d.ts +9 -0
  129. package/dist/utils/logger.d.ts.map +1 -0
  130. package/dist/utils/logger.js +31 -0
  131. package/dist/utils/logger.js.map +1 -0
  132. package/dist/utils/wait.d.ts +21 -0
  133. package/dist/utils/wait.d.ts.map +1 -0
  134. package/dist/utils/wait.js +55 -0
  135. package/dist/utils/wait.js.map +1 -0
  136. package/package.json +67 -0
@@ -0,0 +1,19 @@
1
+ import { type DOMPathSignature } from "../types/element-id.js";
2
+ import type { InteractiveElement } from "../types/page-representation.js";
3
+ export declare class ElementIdGenerator {
4
+ private idToBackendNodeId;
5
+ private backendNodeIdToId;
6
+ private usedIds;
7
+ generateId(elementType: string, role: string, name: string, domPath: DOMPathSignature, backendDOMNodeId: number | null): string;
8
+ resolveId(elementId: string): number | null;
9
+ getIdForBackendNode(backendDOMNodeId: number): string | null;
10
+ findSimilar(elementId: string, currentElements: InteractiveElement[]): InteractiveElement | null;
11
+ clear(): void;
12
+ /**
13
+ * Replace the current maps atomically with new data.
14
+ * Used during re-render to swap in new ID mappings without
15
+ * leaving an empty state between clear() and rebuild.
16
+ */
17
+ replaceWith(other: ElementIdGenerator): void;
18
+ }
19
+ //# sourceMappingURL=element-id-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element-id-generator.d.ts","sourceRoot":"","sources":["../../src/renderer/element-id-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAG1E,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,OAAO,CAAqB;IAEpC,UAAU,CACR,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,gBAAgB,EACzB,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAC9B,MAAM;IAmCT,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAI3C,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAI5D,WAAW,CACT,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,kBAAkB,EAAE,GACpC,kBAAkB,GAAG,IAAI;IAoB5B,KAAK,IAAI,IAAI;IAMb;;;;OAIG;IACH,WAAW,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;CAK7C"}
@@ -0,0 +1,73 @@
1
+ import { TYPE_PREFIX_MAP } from "../types/element-id.js";
2
+ import { hashToHex4 } from "../utils/hash.js";
3
+ export class ElementIdGenerator {
4
+ idToBackendNodeId = new Map();
5
+ backendNodeIdToId = new Map();
6
+ usedIds = new Set();
7
+ generateId(elementType, role, name, domPath, backendDOMNodeId) {
8
+ const prefix = TYPE_PREFIX_MAP[elementType] ?? "el";
9
+ const compositeKey = [
10
+ elementType,
11
+ role,
12
+ name,
13
+ domPath.nearestLandmarkRole ?? "",
14
+ domPath.nearestLandmarkLabel ?? "",
15
+ domPath.nearestLabelledContainer ?? "",
16
+ String(domPath.siblingIndex),
17
+ ].join("|");
18
+ const hexHash = hashToHex4(compositeKey);
19
+ let candidateId = `${prefix}-${hexHash}`;
20
+ // Collision handling: append disambiguator
21
+ if (this.usedIds.has(candidateId)) {
22
+ let disambiguator = 2;
23
+ while (this.usedIds.has(`${candidateId}-${disambiguator}`)) {
24
+ disambiguator++;
25
+ }
26
+ candidateId = `${candidateId}-${disambiguator}`;
27
+ }
28
+ this.usedIds.add(candidateId);
29
+ if (backendDOMNodeId !== null) {
30
+ this.idToBackendNodeId.set(candidateId, backendDOMNodeId);
31
+ this.backendNodeIdToId.set(backendDOMNodeId, candidateId);
32
+ }
33
+ return candidateId;
34
+ }
35
+ resolveId(elementId) {
36
+ return this.idToBackendNodeId.get(elementId) ?? null;
37
+ }
38
+ getIdForBackendNode(backendDOMNodeId) {
39
+ return this.backendNodeIdToId.get(backendDOMNodeId) ?? null;
40
+ }
41
+ findSimilar(elementId, currentElements) {
42
+ // Extract type prefix from the missing ID
43
+ const dashIndex = elementId.indexOf("-");
44
+ if (dashIndex === -1)
45
+ return null;
46
+ const prefix = elementId.substring(0, dashIndex);
47
+ // Find elements with the same prefix (same type)
48
+ const sameType = currentElements.filter((el) => el.id.startsWith(prefix + "-"));
49
+ if (sameType.length === 0)
50
+ return null;
51
+ // If there's exactly one element of the same type, it's likely the one
52
+ if (sameType.length === 1)
53
+ return sameType[0];
54
+ // Otherwise, we can't disambiguate — return null
55
+ return null;
56
+ }
57
+ clear() {
58
+ this.idToBackendNodeId.clear();
59
+ this.backendNodeIdToId.clear();
60
+ this.usedIds.clear();
61
+ }
62
+ /**
63
+ * Replace the current maps atomically with new data.
64
+ * Used during re-render to swap in new ID mappings without
65
+ * leaving an empty state between clear() and rebuild.
66
+ */
67
+ replaceWith(other) {
68
+ this.idToBackendNodeId = new Map(other.idToBackendNodeId);
69
+ this.backendNodeIdToId = new Map(other.backendNodeIdToId);
70
+ this.usedIds = new Set(other.usedIds);
71
+ }
72
+ }
73
+ //# sourceMappingURL=element-id-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element-id-generator.js","sourceRoot":"","sources":["../../src/renderer/element-id-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { ParsedAXNode } from "./accessibility-extractor.js";
2
+ import type { ElementIdGenerator } from "./element-id-generator.js";
3
+ import type { Bounds, InteractiveElement, FormRepresentation } from "../types/page-representation.js";
4
+ interface ExtractionResult {
5
+ elements: InteractiveElement[];
6
+ forms: FormRepresentation[];
7
+ }
8
+ export declare class InteractiveExtractor {
9
+ extractInteractiveElements(rootNodes: ParsedAXNode[], boundsMap: Map<number, Bounds>, idGenerator: ElementIdGenerator): ExtractionResult;
10
+ private buildFormRepresentations;
11
+ }
12
+ export {};
13
+ //# sourceMappingURL=interactive-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive-extractor.d.ts","sourceRoot":"","sources":["../../src/renderer/interactive-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGpE,OAAO,KAAK,EACV,MAAM,EACN,kBAAkB,EAGlB,kBAAkB,EACnB,MAAM,iCAAiC,CAAC;AAqDzC,UAAU,gBAAgB;IACxB,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC7B;AAED,qBAAa,oBAAoB;IAC/B,0BAA0B,CACxB,SAAS,EAAE,YAAY,EAAE,EACzB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,WAAW,EAAE,kBAAkB,GAC9B,gBAAgB;IA6FnB,OAAO,CAAC,wBAAwB;CA8DjC"}
@@ -0,0 +1,161 @@
1
+ import { isInteractiveRole } from "./accessibility-extractor.js";
2
+ import { computeDOMPathSignature } from "./dom-path.js";
3
+ import { ZERO_BOUNDS } from "./layout-extractor.js";
4
+ const ROLE_TO_ELEMENT_TYPE = {
5
+ button: "button",
6
+ link: "link",
7
+ textbox: "text_input",
8
+ searchbox: "text_input",
9
+ combobox: "select",
10
+ listbox: "select",
11
+ checkbox: "checkbox",
12
+ radio: "radio",
13
+ switch: "toggle",
14
+ slider: "range",
15
+ spinbutton: "range",
16
+ menuitem: "button",
17
+ menuitemcheckbox: "checkbox",
18
+ menuitemradio: "radio",
19
+ tab: "button",
20
+ treeitem: "button",
21
+ };
22
+ function mapRoleToElementType(role) {
23
+ return ROLE_TO_ELEMENT_TYPE[role] ?? "button";
24
+ }
25
+ function extractElementState(node) {
26
+ const props = node.properties;
27
+ return {
28
+ enabled: props["disabled"] !== true,
29
+ visible: true, // will be overridden by layout extractor if bounds are zero
30
+ focused: props["focused"] === true,
31
+ checked: props["checked"] === "true" || props["checked"] === true
32
+ ? true
33
+ : props["checked"] === "mixed"
34
+ ? true
35
+ : undefined,
36
+ expanded: props["expanded"] !== undefined
37
+ ? props["expanded"] === true
38
+ : undefined,
39
+ selected: props["selected"] !== undefined
40
+ ? props["selected"] === true
41
+ : undefined,
42
+ required: props["required"] === true ? true : undefined,
43
+ invalid: props["invalid"] !== undefined && props["invalid"] !== "false"
44
+ ? true
45
+ : undefined,
46
+ };
47
+ }
48
+ export class InteractiveExtractor {
49
+ extractInteractiveElements(rootNodes, boundsMap, idGenerator) {
50
+ const elements = [];
51
+ const formNodes = [];
52
+ const traverse = (node) => {
53
+ if (node.role === "form") {
54
+ formNodes.push(node);
55
+ }
56
+ if (isInteractiveRole(node.role)) {
57
+ const elementType = mapRoleToElementType(node.role);
58
+ const domPath = computeDOMPathSignature(node);
59
+ const elementId = idGenerator.generateId(elementType, node.role, node.name, domPath, node.backendDOMNodeId);
60
+ let bounds = null;
61
+ if (node.backendDOMNodeId !== null) {
62
+ bounds = boundsMap.get(node.backendDOMNodeId) ?? null;
63
+ }
64
+ const state = extractElementState(node);
65
+ // If no bounds available, mark as not visible
66
+ if (!bounds || (bounds.w === 0 && bounds.h === 0)) {
67
+ state.visible = false;
68
+ }
69
+ const element = {
70
+ id: elementId,
71
+ type: elementType,
72
+ label: node.name || node.description || "",
73
+ bounds: bounds ?? ZERO_BOUNDS,
74
+ state,
75
+ };
76
+ // Add type-specific fields
77
+ if (elementType === "link") {
78
+ element.href = node.value ?? undefined;
79
+ }
80
+ if (elementType === "text_input" ||
81
+ elementType === "textarea" ||
82
+ elementType === "select") {
83
+ element.value = node.value ?? "";
84
+ }
85
+ // Extract options for select/combobox from children
86
+ if (elementType === "select") {
87
+ const options = [];
88
+ const collectOptions = (optionNode) => {
89
+ if (optionNode.role === "option" ||
90
+ optionNode.role === "listitem") {
91
+ options.push(optionNode.name || optionNode.value || "");
92
+ }
93
+ for (const child of optionNode.children) {
94
+ collectOptions(child);
95
+ }
96
+ };
97
+ for (const child of node.children) {
98
+ collectOptions(child);
99
+ }
100
+ if (options.length > 0) {
101
+ element.options = options;
102
+ }
103
+ }
104
+ elements.push(element);
105
+ }
106
+ for (const child of node.children) {
107
+ traverse(child);
108
+ }
109
+ };
110
+ for (const root of rootNodes) {
111
+ traverse(root);
112
+ }
113
+ // Build form representations
114
+ const forms = this.buildFormRepresentations(formNodes, elements, idGenerator, boundsMap);
115
+ return { elements, forms };
116
+ }
117
+ buildFormRepresentations(formNodes, interactiveElements, idGenerator, boundsMap) {
118
+ const forms = [];
119
+ for (const formNode of formNodes) {
120
+ const domPath = computeDOMPathSignature(formNode);
121
+ const formId = idGenerator.generateId("form", formNode.role, formNode.name, domPath, formNode.backendDOMNodeId);
122
+ // Collect IDs of interactive elements that are descendants of this form
123
+ const formFieldIds = [];
124
+ let submitButtonId = null;
125
+ const collectFields = (node) => {
126
+ if (isInteractiveRole(node.role)) {
127
+ // Find the matching interactive element by backendDOMNodeId
128
+ const matchingElement = interactiveElements.find((el) => {
129
+ if (node.backendDOMNodeId === null)
130
+ return false;
131
+ const resolvedId = idGenerator.resolveId(el.id);
132
+ return resolvedId === node.backendDOMNodeId;
133
+ });
134
+ if (matchingElement) {
135
+ if (node.role === "button" &&
136
+ (node.properties["type"] === "submit" ||
137
+ node.name?.toLowerCase().includes("submit"))) {
138
+ submitButtonId = matchingElement.id;
139
+ }
140
+ else {
141
+ formFieldIds.push(matchingElement.id);
142
+ }
143
+ }
144
+ }
145
+ for (const child of node.children) {
146
+ collectFields(child);
147
+ }
148
+ };
149
+ for (const child of formNode.children) {
150
+ collectFields(child);
151
+ }
152
+ forms.push({
153
+ id: formId,
154
+ fields: formFieldIds,
155
+ submit: submitButtonId,
156
+ });
157
+ }
158
+ return forms;
159
+ }
160
+ }
161
+ //# sourceMappingURL=interactive-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive-extractor.js","sourceRoot":"","sources":["../../src/renderer/interactive-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { CDPSession } from "puppeteer";
2
+ import type { Bounds } from "../types/page-representation.js";
3
+ export declare const ZERO_BOUNDS: Bounds;
4
+ export declare class LayoutExtractor {
5
+ getBounds(session: CDPSession, backendNodeId: number): Promise<Bounds | null>;
6
+ getBoundsForNodes(session: CDPSession, backendNodeIds: number[]): Promise<Map<number, Bounds>>;
7
+ }
8
+ //# sourceMappingURL=layout-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-extractor.d.ts","sourceRoot":"","sources":["../../src/renderer/layout-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAG9D,eAAO,MAAM,WAAW,EAAE,MAAmC,CAAC;AAE9D,qBAAa,eAAe;IACpB,SAAS,CACb,OAAO,EAAE,UAAU,EACnB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA4BnB,iBAAiB,CACrB,OAAO,EAAE,UAAU,EACnB,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAwBhC"}
@@ -0,0 +1,48 @@
1
+ import { logger } from "../utils/logger.js";
2
+ export const ZERO_BOUNDS = { x: 0, y: 0, w: 0, h: 0 };
3
+ export class LayoutExtractor {
4
+ async getBounds(session, backendNodeId) {
5
+ try {
6
+ const result = await session.send("DOM.getBoxModel", {
7
+ backendNodeId,
8
+ });
9
+ const model = result.model;
10
+ if (!model || !model.content)
11
+ return null;
12
+ // content quad is [x1,y1, x2,y2, x3,y3, x4,y4]
13
+ const quad = model.content;
14
+ const minX = Math.min(quad[0], quad[2], quad[4], quad[6]);
15
+ const minY = Math.min(quad[1], quad[3], quad[5], quad[7]);
16
+ const maxX = Math.max(quad[0], quad[2], quad[4], quad[6]);
17
+ const maxY = Math.max(quad[1], quad[3], quad[5], quad[7]);
18
+ return {
19
+ x: Math.round(minX),
20
+ y: Math.round(minY),
21
+ w: Math.round(maxX - minX),
22
+ h: Math.round(maxY - minY),
23
+ };
24
+ }
25
+ catch {
26
+ // Element may be invisible, detached, or zero-size
27
+ return null;
28
+ }
29
+ }
30
+ async getBoundsForNodes(session, backendNodeIds) {
31
+ const boundsMap = new Map();
32
+ // Process in parallel for performance, but cap concurrency
33
+ const batchSize = 50;
34
+ for (let i = 0; i < backendNodeIds.length; i += batchSize) {
35
+ const batch = backendNodeIds.slice(i, i + batchSize);
36
+ const results = await Promise.all(batch.map(async (nodeId) => {
37
+ const bounds = await this.getBounds(session, nodeId);
38
+ return { nodeId, bounds };
39
+ }));
40
+ for (const { nodeId, bounds } of results) {
41
+ boundsMap.set(nodeId, bounds ?? ZERO_BOUNDS);
42
+ }
43
+ }
44
+ logger.debug(`Extracted bounds for ${boundsMap.size}/${backendNodeIds.length} nodes`);
45
+ return boundsMap;
46
+ }
47
+ }
48
+ //# sourceMappingURL=layout-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-extractor.js","sourceRoot":"","sources":["../../src/renderer/layout-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { Page } from "puppeteer";
2
+ import type { CDPSessionManager } from "../browser/cdp-session.js";
3
+ import { ElementIdGenerator } from "./element-id-generator.js";
4
+ import type { PageRepresentation } from "../types/page-representation.js";
5
+ export type DetailLevel = "minimal" | "summary" | "full";
6
+ export interface RenderOptions {
7
+ detail: DetailLevel;
8
+ selector?: string;
9
+ includeStyles?: boolean;
10
+ }
11
+ export declare class RendererPipeline {
12
+ private cdpSessionManager;
13
+ private elementIdGenerator;
14
+ private accessibilityExtractor;
15
+ private layoutExtractor;
16
+ private interactiveExtractor;
17
+ private contentExtractor;
18
+ constructor(cdpSessionManager: CDPSessionManager, elementIdGenerator: ElementIdGenerator);
19
+ render(page: Page, options: RenderOptions): Promise<PageRepresentation>;
20
+ private collectNodesNeedingBounds;
21
+ private isInteractiveNode;
22
+ private extractLandmarks;
23
+ private extractHeadings;
24
+ private getHeadingLevel;
25
+ }
26
+ //# sourceMappingURL=renderer-pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer-pipeline.d.ts","sourceRoot":"","sources":["../../src/renderer/renderer-pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAMnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,KAAK,EACV,kBAAkB,EAInB,MAAM,iCAAiC,CAAC;AAGzC,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,qBAAa,gBAAgB;IAOzB,OAAO,CAAC,iBAAiB;IACzB,OAAO,CAAC,kBAAkB;IAP5B,OAAO,CAAC,sBAAsB,CAAgC;IAC9D,OAAO,CAAC,eAAe,CAAyB;IAChD,OAAO,CAAC,oBAAoB,CAA8B;IAC1D,OAAO,CAAC,gBAAgB,CAA0B;gBAGxC,iBAAiB,EAAE,iBAAiB,EACpC,kBAAkB,EAAE,kBAAkB;IAG1C,MAAM,CACV,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,kBAAkB,CAAC;IA0F9B,OAAO,CAAC,yBAAyB;IAwBjC,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,gBAAgB;IAiCxB,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,eAAe;CAOxB"}
@@ -0,0 +1,163 @@
1
+ import { AccessibilityExtractor, isLandmarkRole, isHeadingRole } from "./accessibility-extractor.js";
2
+ import { LayoutExtractor, ZERO_BOUNDS } from "./layout-extractor.js";
3
+ import { InteractiveExtractor } from "./interactive-extractor.js";
4
+ import { ContentExtractor } from "./content-extractor.js";
5
+ import { ElementIdGenerator } from "./element-id-generator.js";
6
+ import { computeDOMPathSignature } from "./dom-path.js";
7
+ import { logger } from "../utils/logger.js";
8
+ export class RendererPipeline {
9
+ cdpSessionManager;
10
+ elementIdGenerator;
11
+ accessibilityExtractor = new AccessibilityExtractor();
12
+ layoutExtractor = new LayoutExtractor();
13
+ interactiveExtractor = new InteractiveExtractor();
14
+ contentExtractor = new ContentExtractor();
15
+ constructor(cdpSessionManager, elementIdGenerator) {
16
+ this.cdpSessionManager = cdpSessionManager;
17
+ this.elementIdGenerator = elementIdGenerator;
18
+ }
19
+ async render(page, options) {
20
+ const startTime = Date.now();
21
+ logger.debug("Starting render pipeline", { detail: options.detail });
22
+ const session = await this.cdpSessionManager.getSession(page);
23
+ // Step 1: Extract accessibility tree
24
+ const rootNodes = await this.accessibilityExtractor.extract(session);
25
+ // Step 2: Collect nodes that need layout data
26
+ const nodesNeedingBounds = this.collectNodesNeedingBounds(rootNodes);
27
+ const backendNodeIds = nodesNeedingBounds
28
+ .filter((n) => n.backendDOMNodeId !== null)
29
+ .map((n) => n.backendDOMNodeId);
30
+ // Step 3: Extract layout for relevant nodes
31
+ const boundsMap = await this.layoutExtractor.getBoundsForNodes(session, backendNodeIds);
32
+ // Step 4: Build a fresh ID generator for this render
33
+ const freshIdGenerator = new ElementIdGenerator();
34
+ // Step 5: Extract landmarks with bounds
35
+ const landmarks = this.extractLandmarks(rootNodes, boundsMap, freshIdGenerator);
36
+ // Step 6: Extract headings
37
+ const headings = this.extractHeadings(rootNodes, freshIdGenerator);
38
+ // Step 7: Extract interactive elements and forms
39
+ const { elements, forms } = this.interactiveExtractor.extractInteractiveElements(rootNodes, boundsMap, freshIdGenerator);
40
+ // Step 8: Extract content based on detail level
41
+ let contentSummary = "";
42
+ let fullContent;
43
+ if (options.detail !== "minimal") {
44
+ contentSummary = this.contentExtractor.extractSummary(rootNodes);
45
+ }
46
+ if (options.detail === "full") {
47
+ fullContent = this.contentExtractor.extractFullContent(rootNodes);
48
+ }
49
+ // Step 9: Atomically replace the shared ID generator
50
+ this.elementIdGenerator.replaceWith(freshIdGenerator);
51
+ // Step 10: Get page metadata
52
+ const url = page.url();
53
+ const title = await page.title();
54
+ const viewport = page.viewport() ?? { width: 1280, height: 720 };
55
+ const representation = {
56
+ url,
57
+ title,
58
+ viewport: { width: viewport.width, height: viewport.height },
59
+ snapshot_id: 0, // Will be set by snapshot store when pushed
60
+ timestamp: new Date().toISOString(),
61
+ structure: {
62
+ landmarks,
63
+ headings,
64
+ content_summary: contentSummary,
65
+ ...(fullContent !== undefined ? { full_content: fullContent } : {}),
66
+ },
67
+ interactive: elements,
68
+ forms,
69
+ alerts: [],
70
+ errors: {
71
+ console: [],
72
+ network: [],
73
+ },
74
+ };
75
+ logger.debug("Render pipeline complete", {
76
+ duration: Date.now() - startTime,
77
+ landmarks: landmarks.length,
78
+ headings: headings.length,
79
+ interactive: elements.length,
80
+ forms: forms.length,
81
+ });
82
+ return representation;
83
+ }
84
+ collectNodesNeedingBounds(rootNodes) {
85
+ const nodes = [];
86
+ const traverse = (node) => {
87
+ if (isLandmarkRole(node.role) ||
88
+ isHeadingRole(node.role) ||
89
+ this.isInteractiveNode(node)) {
90
+ nodes.push(node);
91
+ }
92
+ for (const child of node.children) {
93
+ traverse(child);
94
+ }
95
+ };
96
+ for (const root of rootNodes) {
97
+ traverse(root);
98
+ }
99
+ return nodes;
100
+ }
101
+ isInteractiveNode(node) {
102
+ const interactiveRoles = new Set([
103
+ "button", "link", "textbox", "combobox", "listbox",
104
+ "checkbox", "radio", "switch", "slider", "spinbutton",
105
+ "searchbox", "menuitem", "menuitemcheckbox", "menuitemradio",
106
+ "tab", "treeitem",
107
+ ]);
108
+ return interactiveRoles.has(node.role);
109
+ }
110
+ extractLandmarks(rootNodes, boundsMap, _idGenerator) {
111
+ const landmarks = [];
112
+ const traverse = (node) => {
113
+ if (isLandmarkRole(node.role)) {
114
+ let bounds = ZERO_BOUNDS;
115
+ if (node.backendDOMNodeId !== null) {
116
+ bounds = boundsMap.get(node.backendDOMNodeId) ?? ZERO_BOUNDS;
117
+ }
118
+ landmarks.push({
119
+ role: node.role,
120
+ label: node.name || node.role,
121
+ bounds,
122
+ });
123
+ }
124
+ for (const child of node.children) {
125
+ traverse(child);
126
+ }
127
+ };
128
+ for (const root of rootNodes) {
129
+ traverse(root);
130
+ }
131
+ return landmarks;
132
+ }
133
+ extractHeadings(rootNodes, idGenerator) {
134
+ const headings = [];
135
+ const traverse = (node) => {
136
+ if (isHeadingRole(node.role)) {
137
+ const level = this.getHeadingLevel(node);
138
+ const domPath = computeDOMPathSignature(node);
139
+ const headingId = idGenerator.generateId("heading", node.role, node.name, domPath, node.backendDOMNodeId);
140
+ headings.push({
141
+ level,
142
+ text: node.name || "",
143
+ id: headingId,
144
+ });
145
+ }
146
+ for (const child of node.children) {
147
+ traverse(child);
148
+ }
149
+ };
150
+ for (const root of rootNodes) {
151
+ traverse(root);
152
+ }
153
+ return headings;
154
+ }
155
+ getHeadingLevel(node) {
156
+ const level = node.properties["level"];
157
+ if (typeof level === "number" && level >= 1 && level <= 6) {
158
+ return level;
159
+ }
160
+ return 2; // default if level not specified
161
+ }
162
+ }
163
+ //# sourceMappingURL=renderer-pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer-pipeline.js","sourceRoot":"","sources":["../../src/renderer/renderer-pipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { BrowserManager } from "./browser/browser-manager.js";
3
+ import type { PageManager } from "./browser/page-manager.js";
4
+ import type { RendererPipeline } from "./renderer/renderer-pipeline.js";
5
+ import type { ElementIdGenerator } from "./renderer/element-id-generator.js";
6
+ import type { SnapshotStore } from "./state/snapshot-store.js";
7
+ import type { CharlotteConfig } from "./types/config.js";
8
+ import type { DevModeState } from "./dev/dev-mode-state.js";
9
+ export interface ServerDeps {
10
+ browserManager: BrowserManager;
11
+ pageManager: PageManager;
12
+ rendererPipeline: RendererPipeline;
13
+ elementIdGenerator: ElementIdGenerator;
14
+ snapshotStore: SnapshotStore;
15
+ config: CharlotteConfig;
16
+ devModeState?: DevModeState;
17
+ }
18
+ export declare function createServer(deps: ServerDeps): McpServer;
19
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAOzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,MAAM,WAAW,UAAU;IACzB,cAAc,EAAE,cAAc,CAAC;IAC/B,WAAW,EAAE,WAAW,CAAC;IACzB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,aAAa,EAAE,aAAa,CAAC;IAC7B,MAAM,EAAE,eAAe,CAAC;IACxB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,CAqCxD"}
package/dist/server.js ADDED
@@ -0,0 +1,39 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { registerEvaluateTools } from "./tools/evaluate.js";
3
+ import { registerNavigationTools } from "./tools/navigation.js";
4
+ import { registerObservationTools } from "./tools/observation.js";
5
+ import { registerInteractionTools } from "./tools/interaction.js";
6
+ import { registerSessionTools } from "./tools/session.js";
7
+ import { registerDevModeTools } from "./tools/dev-mode.js";
8
+ export function createServer(deps) {
9
+ const server = new McpServer({
10
+ name: "charlotte",
11
+ version: "0.1.0",
12
+ }, {
13
+ capabilities: {
14
+ tools: {},
15
+ },
16
+ });
17
+ // Phase 1: evaluate tool
18
+ registerEvaluateTools(server, {
19
+ browserManager: deps.browserManager,
20
+ getActivePage: () => deps.pageManager.getActivePage(),
21
+ });
22
+ // Phase 2–4: all tool modules share the same dependency bundle
23
+ const toolDeps = {
24
+ browserManager: deps.browserManager,
25
+ pageManager: deps.pageManager,
26
+ rendererPipeline: deps.rendererPipeline,
27
+ elementIdGenerator: deps.elementIdGenerator,
28
+ snapshotStore: deps.snapshotStore,
29
+ config: deps.config,
30
+ devModeState: deps.devModeState,
31
+ };
32
+ registerNavigationTools(server, toolDeps);
33
+ registerObservationTools(server, toolDeps);
34
+ registerInteractionTools(server, toolDeps);
35
+ registerSessionTools(server, toolDeps);
36
+ registerDevModeTools(server, toolDeps);
37
+ return server;
38
+ }
39
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAa3D,MAAM,UAAU,YAAY,CAAC,IAAgB;IAC3C,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,OAAO;KACjB,EACD;QACE,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;SACV;KACF,CACF,CAAC;IAEF,yBAAyB;IACzB,qBAAqB,CAAC,MAAM,EAAE;QAC5B,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE;KACtD,CAAC,CAAC;IAEH,+DAA+D;IAC/D,MAAM,QAAQ,GAAG;QACf,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;QACvC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;QAC3C,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,YAAY,EAAE,IAAI,CAAC,YAAY;KAChC,CAAC;IAEF,uBAAuB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC1C,wBAAwB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC3C,wBAAwB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC3C,oBAAoB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvC,oBAAoB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAEvC,OAAO,MAAM,CAAC;AAChB,CAAC"}