frontend-perception-engine 0.1.2__tar.gz → 0.2.0__tar.gz

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 (64) hide show
  1. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/PKG-INFO +17 -1
  2. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/README.md +15 -0
  3. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/pyproject.toml +2 -1
  4. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/frontend_perception_engine.egg-info/PKG-INFO +17 -1
  5. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/frontend_perception_engine.egg-info/SOURCES.txt +4 -0
  6. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/frontend_perception_engine.egg-info/requires.txt +1 -0
  7. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/cli/install.py +4 -1
  8. frontend_perception_engine-0.2.0/src/navigation/mcp/diff.py +68 -0
  9. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/envelope.py +19 -10
  10. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/handlers.py +201 -91
  11. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/instructions.py +4 -2
  12. frontend_perception_engine-0.2.0/src/navigation/mcp/resources.py +108 -0
  13. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/server.py +5 -4
  14. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/tools.py +37 -11
  15. frontend_perception_engine-0.2.0/src/navigation/mcp/visual_response.py +103 -0
  16. frontend_perception_engine-0.2.0/src/navigation/perception/observation.py +121 -0
  17. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/scan.py +11 -1
  18. frontend_perception_engine-0.2.0/src/navigation/perception/visual_capture.py +211 -0
  19. frontend_perception_engine-0.2.0/src/navigation/perception/visual_diff.py +101 -0
  20. frontend_perception_engine-0.2.0/src/navigation/perception/visual_insights.py +163 -0
  21. frontend_perception_engine-0.1.2/src/navigation/mcp/diff.py +0 -28
  22. frontend_perception_engine-0.1.2/src/navigation/mcp/resources.py +0 -82
  23. frontend_perception_engine-0.1.2/src/navigation/perception/observation.py +0 -97
  24. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/setup.cfg +0 -0
  25. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/frontend_perception_engine.egg-info/dependency_links.txt +0 -0
  26. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/frontend_perception_engine.egg-info/entry_points.txt +0 -0
  27. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/frontend_perception_engine.egg-info/top_level.txt +0 -0
  28. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/__init__.py +0 -0
  29. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/browser_use/__init__.py +0 -0
  30. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/browser_use/agent_runner.py +0 -0
  31. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/browser_use/hints.py +0 -0
  32. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/browser_use/integration.py +0 -0
  33. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/browser_use/llm.py +0 -0
  34. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/cli/__init__.py +0 -0
  35. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/codeGraph/__init__.py +0 -0
  36. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/codeGraph/crg_impl.py +0 -0
  37. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/codeGraph/factory.py +0 -0
  38. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/codeGraph/interface.py +0 -0
  39. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/codeGraph/null_impl.py +0 -0
  40. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/__init__.py +0 -0
  41. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/__main__.py +0 -0
  42. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/scan_registry.py +0 -0
  43. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/session_store.py +0 -0
  44. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/__init__.py +0 -0
  45. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/artifacts.py +0 -0
  46. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/auth_gate.py +0 -0
  47. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/budget.py +0 -0
  48. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/cdp_hub.py +0 -0
  49. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/dev_insights.py +0 -0
  50. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/exploration.py +0 -0
  51. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/feature_flags.py +0 -0
  52. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/file_upload.py +0 -0
  53. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/flow_graph.py +0 -0
  54. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/form_probe.py +0 -0
  55. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/iframe_context.py +0 -0
  56. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/preflight.py +0 -0
  57. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/rich_editors.py +0 -0
  58. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/route_guards.py +0 -0
  59. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/runner.py +0 -0
  60. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/scripted_actions.py +0 -0
  61. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/state_manager.py +0 -0
  62. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/verification.py +0 -0
  63. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/virtual_scroll.py +0 -0
  64. {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/websocket_observer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontend-perception-engine
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Frontend perception engine with optional CRG-powered navigation hints for Browser Use.
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -8,6 +8,7 @@ Requires-Dist: browser-use>=0.13.3
8
8
  Requires-Dist: code-review-graph>=2.3.6
9
9
  Requires-Dist: python-dotenv>=1.0.0
10
10
  Requires-Dist: mcp>=1.0.0
11
+ Requires-Dist: pillow>=10.0.0
11
12
  Provides-Extra: aws
12
13
  Requires-Dist: boto3>=1.35.0; extra == "aws"
13
14
 
@@ -55,12 +56,25 @@ Your coding agent (Cursor/Claude/Codex) remains the brain.
55
56
 
56
57
  ### Install
57
58
 
59
+ Both PyPI names install the same MCP server:
60
+
61
+ | Package | Install |
62
+ |---------|---------|
63
+ | `frontend-perception-engine` | `pip install frontend-perception-engine` |
64
+ | `frontend-mcp` (alias) | `pip install frontend-mcp` |
65
+
58
66
  Recommended (quiet output + next steps):
59
67
 
60
68
  ```bash
61
69
  uvx --from frontend-perception-engine frontend-perception-install
62
70
  ```
63
71
 
72
+ Or the shorter alias name:
73
+
74
+ ```bash
75
+ uvx --from frontend-mcp frontend-mcp-install
76
+ ```
77
+
64
78
  With Chromium for Browser Use:
65
79
 
66
80
  ```bash
@@ -97,6 +111,8 @@ Using `uvx` (no local install in current environment):
97
111
 
98
112
  ```bash
99
113
  uvx --from frontend-perception-engine frontend-perception-mcp
114
+ # or
115
+ uvx --from frontend-mcp frontend-mcp
100
116
  ```
101
117
 
102
118
  ### Cursor MCP config
@@ -42,12 +42,25 @@ Your coding agent (Cursor/Claude/Codex) remains the brain.
42
42
 
43
43
  ### Install
44
44
 
45
+ Both PyPI names install the same MCP server:
46
+
47
+ | Package | Install |
48
+ |---------|---------|
49
+ | `frontend-perception-engine` | `pip install frontend-perception-engine` |
50
+ | `frontend-mcp` (alias) | `pip install frontend-mcp` |
51
+
45
52
  Recommended (quiet output + next steps):
46
53
 
47
54
  ```bash
48
55
  uvx --from frontend-perception-engine frontend-perception-install
49
56
  ```
50
57
 
58
+ Or the shorter alias name:
59
+
60
+ ```bash
61
+ uvx --from frontend-mcp frontend-mcp-install
62
+ ```
63
+
51
64
  With Chromium for Browser Use:
52
65
 
53
66
  ```bash
@@ -84,6 +97,8 @@ Using `uvx` (no local install in current environment):
84
97
 
85
98
  ```bash
86
99
  uvx --from frontend-perception-engine frontend-perception-mcp
100
+ # or
101
+ uvx --from frontend-mcp frontend-mcp
87
102
  ```
88
103
 
89
104
  ### Cursor MCP config
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "frontend-perception-engine"
3
- version = "0.1.2"
3
+ version = "0.2.0"
4
4
  description = "Frontend perception engine with optional CRG-powered navigation hints for Browser Use."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -9,6 +9,7 @@ dependencies = [
9
9
  "code-review-graph>=2.3.6",
10
10
  "python-dotenv>=1.0.0",
11
11
  "mcp>=1.0.0",
12
+ "pillow>=10.0.0",
12
13
  ]
13
14
 
14
15
  [project.scripts]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontend-perception-engine
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Frontend perception engine with optional CRG-powered navigation hints for Browser Use.
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -8,6 +8,7 @@ Requires-Dist: browser-use>=0.13.3
8
8
  Requires-Dist: code-review-graph>=2.3.6
9
9
  Requires-Dist: python-dotenv>=1.0.0
10
10
  Requires-Dist: mcp>=1.0.0
11
+ Requires-Dist: pillow>=10.0.0
11
12
  Provides-Extra: aws
12
13
  Requires-Dist: boto3>=1.35.0; extra == "aws"
13
14
 
@@ -55,12 +56,25 @@ Your coding agent (Cursor/Claude/Codex) remains the brain.
55
56
 
56
57
  ### Install
57
58
 
59
+ Both PyPI names install the same MCP server:
60
+
61
+ | Package | Install |
62
+ |---------|---------|
63
+ | `frontend-perception-engine` | `pip install frontend-perception-engine` |
64
+ | `frontend-mcp` (alias) | `pip install frontend-mcp` |
65
+
58
66
  Recommended (quiet output + next steps):
59
67
 
60
68
  ```bash
61
69
  uvx --from frontend-perception-engine frontend-perception-install
62
70
  ```
63
71
 
72
+ Or the shorter alias name:
73
+
74
+ ```bash
75
+ uvx --from frontend-mcp frontend-mcp-install
76
+ ```
77
+
64
78
  With Chromium for Browser Use:
65
79
 
66
80
  ```bash
@@ -97,6 +111,8 @@ Using `uvx` (no local install in current environment):
97
111
 
98
112
  ```bash
99
113
  uvx --from frontend-perception-engine frontend-perception-mcp
114
+ # or
115
+ uvx --from frontend-mcp frontend-mcp
100
116
  ```
101
117
 
102
118
  ### Cursor MCP config
@@ -30,6 +30,7 @@ src/navigation/mcp/scan_registry.py
30
30
  src/navigation/mcp/server.py
31
31
  src/navigation/mcp/session_store.py
32
32
  src/navigation/mcp/tools.py
33
+ src/navigation/mcp/visual_response.py
33
34
  src/navigation/perception/__init__.py
34
35
  src/navigation/perception/artifacts.py
35
36
  src/navigation/perception/auth_gate.py
@@ -52,4 +53,7 @@ src/navigation/perception/scripted_actions.py
52
53
  src/navigation/perception/state_manager.py
53
54
  src/navigation/perception/verification.py
54
55
  src/navigation/perception/virtual_scroll.py
56
+ src/navigation/perception/visual_capture.py
57
+ src/navigation/perception/visual_diff.py
58
+ src/navigation/perception/visual_insights.py
55
59
  src/navigation/perception/websocket_observer.py
@@ -2,6 +2,7 @@ browser-use>=0.13.3
2
2
  code-review-graph>=2.3.6
3
3
  python-dotenv>=1.0.0
4
4
  mcp>=1.0.0
5
+ pillow>=10.0.0
5
6
 
6
7
  [aws]
7
8
  boto3>=1.35.0
@@ -127,7 +127,9 @@ def _print_success(*, with_browser: bool) -> None:
127
127
  sys.stdout.write(' frontend-perception-mcp\n\n')
128
128
  sys.stdout.write(' Or with uvx (no global install):\n')
129
129
  sys.stdout.write(' uvx --from frontend-perception-engine frontend-perception-mcp\n\n')
130
- sys.stdout.write(' Cursor MCP config:\n')
130
+ sys.stdout.write(' Or shorter PyPI name:\n')
131
+ sys.stdout.write(' uvx --from frontend-mcp frontend-mcp\n\n')
132
+ sys.stdout.write(' Cursor MCP config (either name):\n')
131
133
  sys.stdout.write(' {\n')
132
134
  sys.stdout.write(' "mcpServers": {\n')
133
135
  sys.stdout.write(' "frontend-perception": {\n')
@@ -136,6 +138,7 @@ def _print_success(*, with_browser: bool) -> None:
136
138
  sys.stdout.write(' }\n')
137
139
  sys.stdout.write(' }\n')
138
140
  sys.stdout.write(' }\n')
141
+ sys.stdout.write('\n Alias package: pip install frontend-mcp → frontend-mcp / frontend-mcp-install\n')
139
142
  if with_browser:
140
143
  sys.stdout.write('\n Chromium is ready for Browser Use.\n')
141
144
  sys.stdout.flush()
@@ -0,0 +1,68 @@
1
+ """Compare two observation snapshots by scan_id."""
2
+ from __future__ import annotations
3
+
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ from navigation.perception.visual_diff import VisualDiffResult, diff_screenshot_files
8
+
9
+
10
+ def _blocking_issues(obs: dict[str, Any]) -> list[str]:
11
+ di = obs.get('dev_insights') or {}
12
+ summary = di.get('summary') or {}
13
+ blocking = list(summary.get('blocking_issues') or [])
14
+ visual = obs.get('visual_insights') or {}
15
+ blocking.extend(visual.get('blocking') or [])
16
+ return blocking
17
+
18
+
19
+ def _visual_issues_delta(before: dict[str, Any], after: dict[str, Any]) -> dict[str, list[str]]:
20
+ b_vis = set((before.get('visual_insights') or {}).get('blocking') or [])
21
+ a_vis = set((after.get('visual_insights') or {}).get('blocking') or [])
22
+ return {
23
+ 'new_visual_blocking': sorted(a_vis - b_vis),
24
+ 'removed_visual_blocking': sorted(b_vis - a_vis),
25
+ }
26
+
27
+
28
+ def diff_observations(
29
+ before: dict[str, Any],
30
+ after: dict[str, Any],
31
+ *,
32
+ artifacts_dir: Path | None = None,
33
+ scan_id_before: str = '',
34
+ scan_id_after: str = '',
35
+ ) -> dict[str, Any]:
36
+ b_block = set(_blocking_issues(before))
37
+ a_block = set(_blocking_issues(after))
38
+ b_dom = str(before.get('dom_text') or '')
39
+ a_dom = str(after.get('dom_text') or '')
40
+ excerpt_len = 500
41
+ visual_delta = _visual_issues_delta(before, after)
42
+
43
+ result: dict[str, Any] = {
44
+ 'url_before': before.get('url') or '',
45
+ 'url_after': after.get('url') or '',
46
+ 'url_changed': (before.get('url') or '') != (after.get('url') or ''),
47
+ 'dom_text_changed': b_dom != a_dom,
48
+ 'new_blocking_issues': sorted(a_block - b_block),
49
+ 'removed_blocking_issues': sorted(b_block - a_block),
50
+ 'dom_excerpt_before': b_dom[:excerpt_len],
51
+ 'dom_excerpt_after': a_dom[:excerpt_len],
52
+ **visual_delta,
53
+ 'visual_diff': None,
54
+ }
55
+
56
+ before_shot = before.get('annotated_screenshot_path') or before.get('screenshot_path')
57
+ after_shot = after.get('annotated_screenshot_path') or after.get('screenshot_path')
58
+ if artifacts_dir and before_shot and after_shot:
59
+ prefix = f'{scan_id_before}_vs_{scan_id_after}'.replace('/', '_')[:80]
60
+ vd: VisualDiffResult = diff_screenshot_files(
61
+ before_shot,
62
+ after_shot,
63
+ artifacts_dir / 'diffs',
64
+ prefix=prefix,
65
+ )
66
+ result['visual_diff'] = vd.to_dict()
67
+
68
+ return result
@@ -38,13 +38,22 @@ def envelope_json(**kwargs: Any) -> str:
38
38
 
39
39
 
40
40
  def agent_summary_from_observation(obs_dict: dict[str, Any]) -> dict[str, Any]:
41
- """Compact summary for host agent reasoning (no planning hints)."""
42
- di = obs_dict.get("dev_insights") or {}
43
- summary = di.get("summary") or {}
44
- page_meta = di.get("page_meta")
45
- return {
46
- "blocking": summary.get("blocking_issues") or [],
47
- "advisory": summary.get("advisory_issues") or [],
48
- "page_meta": page_meta,
49
- "degraded": list(obs_dict.get("degraded") or []) + list(di.get("degraded") or []),
50
- }
41
+ """Compact summary for host agent reasoning (no planning hints)."""
42
+ di = obs_dict.get('dev_insights') or {}
43
+ summary = di.get('summary') or {}
44
+ page_meta = di.get('page_meta')
45
+ blocking = list(summary.get('blocking_issues') or [])
46
+ advisory = list(summary.get('advisory_issues') or [])
47
+ visual = obs_dict.get('visual_insights') or {}
48
+ for item in visual.get('blocking') or []:
49
+ if item not in blocking:
50
+ blocking.append(item)
51
+ for item in visual.get('advisory') or []:
52
+ if item not in advisory:
53
+ advisory.append(item)
54
+ return {
55
+ 'blocking': blocking,
56
+ 'advisory': advisory,
57
+ 'page_meta': page_meta,
58
+ 'degraded': list(obs_dict.get('degraded') or []) + list(di.get('degraded') or []),
59
+ }