|
10202
|
468
|
9
|
2026-05-08T17:11:09.383697+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260269383_m2.jpg...
|
Firefox
|
AFFiNE - All In One KnowledgeOS — Personal
|
1
|
affine.pro
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
logo
Product
Product
Team
Team
Download
Download
Resources
Pricing
Pricing
Get Started
Get Started
github
Stars on GitHub
AFFiNE AI - AI partner to better write, draw & present | Product Hunt
Write, Draw, Plan,All at Once. With AI.
Write,
Draw,
Plan,
All at Once.
With
AI.
AFFiNE is a workspace with fully merged docs, whiteboards and databases.
Get more things done, your creativity isn’t monotone.
Get Started
Get Started
Trusted by people from next-gen startups to established organizations.
Trusted by people from next-gen startups to established organizations.
Consolidate Your Workflow with Ease on a Hyperfused Platform
Consolidate Your Workflow with Ease on a Hyperfused Platform
Say goodbye to the hassle of switchover
Tired of switching between different tools to meet your complex needs?
Stay focused, and unleash your wild creativity with AFFiNE
Your all-in-one KnowledgeOS solution for effortlessly writing, drawing, and planning on a hyper-fused platform.
Privacy-focused, local-first
You are in charge of your own data.
your way to better productivity
your way to better productivity
Build up your content like blocks and let your ideas run wild.
Draw and visualise with ease and creativity
Draw
and visualise with
ease
and
creativity
Visualise your creativity with others. No constraints, limited only by your imagination.
Plan, track, and collaborate efficiently
Plan, track, and collaborate efficiently
Stay on top of your workload and achieve more in less time.
AI partner helps you better write, draw and plan
AI
partner helps you better write, draw and plan
Let you think bigger, create faster, work smarter in anytime, anywhere
learn more
Learn more
Learn more
Ready-to-Use Templates for Any Project
Ready-to-Use Templates for Any Project
Find your ideal template now
Find your ideal template now
Digital Planner
Digital Planner
Story Board
Story Board
Cornell Notes
Cornell Notes
One Pager
One Pager
Checklist
Checklist
Vision Board
Vision Board
Itinerary template
Itinerary template
AFFiNE builds everything in public
AFFiNE builds
everything in public
Open-Source Code for Trust and Collaboration
Open-Source Code for Trust and Collaboration
We foster trust and enable everyone to contribute and enhance AFFiNE for a far wider audience.
toeverything/AFFiNE/issues
Open issues
Closed
Free for individuals, commercial and team usage fees apply.
$$$
Free
$$$
User-Centric Community Engagement
User-Centric Community Engagement
Creating a vibrant space for users to connect, share, and inspire one another.
Join Our Community
Join Our Community
Millions love to engage and propel the unparalleled AFFiNE
Millions love to engage and
propel the unparalleled
AFFiNE
Dan Charles
CEO - The Keyman Group
Really impressed with how
AFFiNE
is able to streamline our team's workflow and improve productivity. Switch between different modes to write, draw, and plan all in one place and with data security which we are most concerned about. It makes everything easy.
Orange-Cheng
Product manager of the TATDOD Space
Extremely impressed with the quality and capabilities of
AFFiNE
, particularly its simple and intuitive interface. The attention to detail that has been put into every aspect of the product, from its design to its functionality, is truly exceptional. The product's innovative features and capabilities are sure to make a significant impact in the industry, providing customers with a seamless and user-friendly experience.
Maestro
Graphic Designer
With
AFFiNE
's whiteboard feature, I sketch, doodle, and visualize ideas collaboratively in real time. It's an endless canvas for our creativity, allowing us to refine our projects to perfection. The Kanban boards complement our artistic process, ensuring impeccable organization and project tracking.
TinsFox
Front-end Developer
AFFiNE
is by far the best open-source community I’ve come across. Open, inclusive and user-first. At the same time,
AFFiNE
is also a great product. Being open source means more possibilities and more exciting things can be created.
Eliot
Student
AFFiNE
is an open source that is close to its community and filled with useful features. I use edgeless mode to connect all my knowledge to a single page.
Summer123
The Founder of a fashion brand
AFFiNE
's Kanban project management simplifies my hectic workload. Easy task management feels like a personal assistant. Yet, the standout is the whiteboard, streamlining brainstorming, project planning, and workflow visualization.
Joanna
Marketing Manager
AFFiNE
revolutionizes our creative collaboration. Kanban boards effortlessly manage tasks and campaigns. The whiteboard sparks innovation for marketing strategies and content planning, making
AFFiNE
a vital tool for our creative team.
Ragma.TP
Project manager of Tiktok
I'm thrilled with how effortless it was to set up workspaces, arrange pages, and collaborate with my team members in real-time.
AFFiNE
just makes everything easy, streamlines our workflow and boosts our productivity.
Mattias
Student
I've been looking for an open-source note-taking solution for ages now and
AFFiNE
is the first to support all the features I need -- and it even manages to do this while being absolutely beautiful!
AFFiNE
is very feature rich and the synchronization is also awesome.
BusyBee
Full-time Mom
Being a working mom with a hectic schedule,
AFFiNE
is my ultimate lifesaver. Its Kanban boards help me manage household tasks, kids' activities, and work projects with ease. Whether it's organizing chores, tracking school events, or managing deadlines,
AFFiNE
's Kanban feature keeps me on top of it all.
Alice
Student from KCL
One feature I particularly appreciate is the ability to seamlessly switch from typing to handwriting, adding a touch of elegance and versatility to my work.
PanicN3xus
User
AFFiNE
is an exceptional project that elevates note-making to a whole new level. I am highly impressed by the number of features that it brings to the table. Having tried several other open-source note-making software, I can confidently say that
AFFiNE
is the best.
Dynamo
Freelancer
AFFiNE
's Kanban boards are my go-to for life organization, promoting discipline, and habit consistency. I outline goals, plan, and track progress, be it fitness or reading challenges. It's my trusted tool for a fulfilling, disciplined life.
Write Smarter, Work Better with AFFiNE
Write Smarter, Work Better with AFFiNE
Explore the features today, collaborate tomorrow.
Desktop App
Download App
Download App
Mobile App
iOS App
iOS App
Android App
Android App
logo
Company
Terms
Terms
Privacy
Privacy
About Us
About Us
Download
iOS & Android
iOS & Android
Mac & Windows
Mac & Windows
Web Clipper
Web Clipper
Resources
Docs
Docs
Blog
Blog
Templates
Templates
What’s new
What’s new
Community
Community
Timers
Timers
Open Source
AFFiNE
AFFiNE
BlockSuite
BlockSuite
OctoBase
OctoBase
Connect
X (Twitter)
X (Twitter)
GitHub
GitHub
Discord
Discord
YouTube
YouTube
Reddit
Reddit
©2026 Toeverything
·
To Shape, Not to Adapt....
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"bounds":{"left":0.26097074,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"bounds":{"left":0.27426863,"top":0.09577015,"width":0.03025266,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"bounds":{"left":0.26097074,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"bounds":{"left":0.27426863,"top":0.12849163,"width":0.05069814,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.26097074,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.27426863,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.26097074,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.27426863,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.26097074,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.27426863,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.26097074,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.27426863,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"bounds":{"left":0.26097074,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"bounds":{"left":0.27426863,"top":0.32482043,"width":0.105884306,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"bounds":{"left":0.26097074,"top":0.3463687,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":5,"bounds":{"left":0.27426863,"top":0.3575419,"width":0.05851064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.36236703,"top":0.35355148,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.26379654,"top":0.38068634,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.26379654,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.27476728,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.28590426,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.29704124,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.3081782,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"logo","depth":9,"bounds":{"left":0.5078125,"top":0.06943336,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Product","depth":9,"bounds":{"left":0.52642953,"top":0.06783719,"width":0.031416222,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Product","depth":10,"bounds":{"left":0.5304189,"top":0.075418994,"width":0.016788565,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Team","depth":9,"bounds":{"left":0.55917555,"top":0.06783719,"width":0.02642952,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Team","depth":10,"bounds":{"left":0.5631649,"top":0.075418994,"width":0.011801862,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Download","depth":9,"bounds":{"left":0.58693486,"top":0.06783719,"width":0.029587766,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Download","depth":10,"bounds":{"left":0.5909242,"top":0.075418994,"width":0.021609042,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Resources","depth":10,"bounds":{"left":0.6218417,"top":0.075418994,"width":0.022606382,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pricing","depth":9,"bounds":{"left":0.65641624,"top":0.06783719,"width":0.022772606,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pricing","depth":10,"bounds":{"left":0.6604056,"top":0.075418994,"width":0.014793883,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Get Started","depth":10,"bounds":{"left":0.7727726,"top":0.070231445,"width":0.034906916,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Get Started","depth":11,"bounds":{"left":0.7727726,"top":0.070231445,"width":0.034906916,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"github","depth":10,"bounds":{"left":0.8116689,"top":0.06943336,"width":0.052526597,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Stars on GitHub","depth":12,"bounds":{"left":0.8249667,"top":0.075418994,"width":0.03357713,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE AI - AI partner to better write, draw & present | Product Hunt","depth":9,"bounds":{"left":0.91023934,"top":0.9660814,"width":0.0831117,"height":0.023543496},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Write, Draw, Plan,All at Once. With AI.","depth":9,"bounds":{"left":0.5681516,"top":0.21308859,"width":0.23836437,"height":0.14844373},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Write,","depth":10,"bounds":{"left":0.57047874,"top":0.20550679,"width":0.072307184,"height":0.08739027},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Draw,","depth":11,"bounds":{"left":0.64511305,"top":0.18754987,"width":0.0709774,"height":0.13647246},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Plan,","depth":10,"bounds":{"left":0.74617684,"top":0.21109338,"width":0.060339097,"height":0.08739027},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"All at Once.","depth":10,"bounds":{"left":0.5787899,"top":0.2821229,"width":0.13912898,"height":0.08739027},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"With","depth":10,"bounds":{"left":0.7179189,"top":0.29608938,"width":0.05319149,"height":0.06743815},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AI.","depth":11,"bounds":{"left":0.77111036,"top":0.29608938,"width":0.024767287,"height":0.06743815},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE is a workspace with fully merged docs, whiteboards and databases.\nGet more things done, your creativity isn’t monotone.","depth":10,"bounds":{"left":0.5718085,"top":0.37230647,"width":0.23105054,"height":0.041101355},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Get Started","depth":9,"bounds":{"left":0.6575798,"top":0.4142059,"width":0.059507977,"height":0.06304868},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Get Started","depth":10,"bounds":{"left":0.6575798,"top":0.44293696,"width":0.059507977,"height":0.03431764},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Trusted by people from next-gen startups to established organizations.","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trusted by people from next-gen startups to established organizations.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Consolidate Your Workflow with Ease on a Hyperfused Platform","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Consolidate Your Workflow with Ease on a Hyperfused Platform","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Say goodbye to the hassle of switchover","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tired of switching between different tools to meet your complex needs?","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stay focused, and unleash your wild creativity with AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Your all-in-one KnowledgeOS solution for effortlessly writing, drawing, and planning on a hyper-fused platform.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Privacy-focused, local-first","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You are in charge of your own data.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"your way to better productivity","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"your way to better productivity","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Build up your content like blocks and let your ideas run wild.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Draw and visualise with ease and creativity","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Draw","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and visualise with","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ease","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"creativity","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Visualise your creativity with others. No constraints, limited only by your imagination.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Plan, track, and collaborate efficiently","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Plan, track, and collaborate efficiently","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stay on top of your workload and achieve more in less time.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"AI partner helps you better write, draw and plan","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AI","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"partner helps you better write, draw and plan","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let you think bigger, create faster, work smarter in anytime, anywhere","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"learn more","depth":8,"on_screen":false,"help_text":"Learn more about AFFiNE AI","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Learn more","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Learn more","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Ready-to-Use Templates for Any Project","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ready-to-Use Templates for Any Project","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Find your ideal template now","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Find your ideal template now","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Digital Planner","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Digital Planner","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Story Board","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Story Board","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Cornell Notes","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Cornell Notes","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"One Pager","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"One Pager","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Checklist","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checklist","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vision Board","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vision Board","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Itinerary template","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Itinerary template","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"AFFiNE builds everything in public","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE builds\neverything in public","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Open-Source Code for Trust and Collaboration","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open-Source Code for Trust and Collaboration","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"We foster trust and enable everyone to contribute and enhance AFFiNE for a far wider audience.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"toeverything/AFFiNE/issues","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open issues","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Closed","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Free for individuals, commercial and team usage fees apply.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$$$","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Free","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$$$","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"User-Centric Community Engagement","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"User-Centric Community Engagement","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Creating a vibrant space for users to connect, share, and inspire one another.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Join Our Community","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Join Our Community","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Millions love to engage and propel the unparalleled AFFiNE","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Millions love to engage and\npropel the unparalleled","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dan Charles","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CEO - The Keyman Group","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Really impressed with how","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is able to streamline our team's workflow and improve productivity. Switch between different modes to write, draw, and plan all in one place and with data security which we are most concerned about. It makes everything easy.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Orange-Cheng","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Product manager of the TATDOD Space","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Extremely impressed with the quality and capabilities of","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", particularly its simple and intuitive interface. The attention to detail that has been put into every aspect of the product, from its design to its functionality, is truly exceptional. The product's innovative features and capabilities are sure to make a significant impact in the industry, providing customers with a seamless and user-friendly experience.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Maestro","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Graphic Designer","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"With","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'s whiteboard feature, I sketch, doodle, and visualize ideas collaboratively in real time. It's an endless canvas for our creativity, allowing us to refine our projects to perfection. The Kanban boards complement our artistic process, ensuring impeccable organization and project tracking.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TinsFox","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Front-end Developer","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is by far the best open-source community I’ve come across. Open, inclusive and user-first. At the same time,","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is also a great product. Being open source means more possibilities and more exciting things can be created.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Eliot","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Student","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is an open source that is close to its community and filled with useful features. I use edgeless mode to connect all my knowledge to a single page.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Summer123","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Founder of a fashion brand","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'s Kanban project management simplifies my hectic workload. Easy task management feels like a personal assistant. Yet, the standout is the whiteboard, streamlining brainstorming, project planning, and workflow visualization.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Joanna","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Marketing Manager","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"revolutionizes our creative collaboration. Kanban boards effortlessly manage tasks and campaigns. The whiteboard sparks innovation for marketing strategies and content planning, making","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"a vital tool for our creative team.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ragma.TP","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Project manager of Tiktok","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I'm thrilled with how effortless it was to set up workspaces, arrange pages, and collaborate with my team members in real-time.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"just makes everything easy, streamlines our workflow and boosts our productivity.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mattias","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Student","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I've been looking for an open-source note-taking solution for ages now and","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is the first to support all the features I need -- and it even manages to do this while being absolutely beautiful!","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is very feature rich and the synchronization is also awesome.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BusyBee","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Full-time Mom","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Being a working mom with a hectic schedule,","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is my ultimate lifesaver. Its Kanban boards help me manage household tasks, kids' activities, and work projects with ease. Whether it's organizing chores, tracking school events, or managing deadlines,","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'s Kanban feature keeps me on top of it all.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Alice","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Student from KCL","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"One feature I particularly appreciate is the ability to seamlessly switch from typing to handwriting, adding a touch of elegance and versatility to my work.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PanicN3xus","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"User","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is an exceptional project that elevates note-making to a whole new level. I am highly impressed by the number of features that it brings to the table. Having tried several other open-source note-making software, I can confidently say that","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is the best.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamo","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Freelancer","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'s Kanban boards are my go-to for life organization, promoting discipline, and habit consistency. I outline goals, plan, and track progress, be it fitness or reading challenges. It's my trusted tool for a fulfilling, disciplined life.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Write Smarter, Work Better with AFFiNE","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Write Smarter, Work Better with AFFiNE","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Explore the features today, collaborate tomorrow.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Desktop App","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Download App","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Download App","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mobile App","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"iOS App","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"iOS App","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Android App","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Android App","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"logo","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Company","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Terms","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Terms","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Privacy","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Privacy","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"About Us","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"About Us","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Download","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"iOS & Android","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"iOS & Android","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Mac & Windows","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Mac & Windows","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Web Clipper","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Web Clipper","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Resources","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Docs","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Docs","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Blog","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Blog","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Templates","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Templates","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"What’s new","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"What’s new","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Community","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Community","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Timers","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Timers","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open Source","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"BlockSuite","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BlockSuite","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"OctoBase","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"OctoBase","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Connect","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"X (Twitter)","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"X (Twitter)","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Discord","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Discord","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"YouTube","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"YouTube","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reddit","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reddit","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"©2026 Toeverything","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"·","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To Shape, Not to Adapt.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-4170297153369307471
|
8865797968954165063
|
visual_change
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
logo
Product
Product
Team
Team
Download
Download
Resources
Pricing
Pricing
Get Started
Get Started
github
Stars on GitHub
AFFiNE AI - AI partner to better write, draw & present | Product Hunt
Write, Draw, Plan,All at Once. With AI.
Write,
Draw,
Plan,
All at Once.
With
AI.
AFFiNE is a workspace with fully merged docs, whiteboards and databases.
Get more things done, your creativity isn’t monotone.
Get Started
Get Started
Trusted by people from next-gen startups to established organizations.
Trusted by people from next-gen startups to established organizations.
Consolidate Your Workflow with Ease on a Hyperfused Platform
Consolidate Your Workflow with Ease on a Hyperfused Platform
Say goodbye to the hassle of switchover
Tired of switching between different tools to meet your complex needs?
Stay focused, and unleash your wild creativity with AFFiNE
Your all-in-one KnowledgeOS solution for effortlessly writing, drawing, and planning on a hyper-fused platform.
Privacy-focused, local-first
You are in charge of your own data.
your way to better productivity
your way to better productivity
Build up your content like blocks and let your ideas run wild.
Draw and visualise with ease and creativity
Draw
and visualise with
ease
and
creativity
Visualise your creativity with others. No constraints, limited only by your imagination.
Plan, track, and collaborate efficiently
Plan, track, and collaborate efficiently
Stay on top of your workload and achieve more in less time.
AI partner helps you better write, draw and plan
AI
partner helps you better write, draw and plan
Let you think bigger, create faster, work smarter in anytime, anywhere
learn more
Learn more
Learn more
Ready-to-Use Templates for Any Project
Ready-to-Use Templates for Any Project
Find your ideal template now
Find your ideal template now
Digital Planner
Digital Planner
Story Board
Story Board
Cornell Notes
Cornell Notes
One Pager
One Pager
Checklist
Checklist
Vision Board
Vision Board
Itinerary template
Itinerary template
AFFiNE builds everything in public
AFFiNE builds
everything in public
Open-Source Code for Trust and Collaboration
Open-Source Code for Trust and Collaboration
We foster trust and enable everyone to contribute and enhance AFFiNE for a far wider audience.
toeverything/AFFiNE/issues
Open issues
Closed
Free for individuals, commercial and team usage fees apply.
$$$
Free
$$$
User-Centric Community Engagement
User-Centric Community Engagement
Creating a vibrant space for users to connect, share, and inspire one another.
Join Our Community
Join Our Community
Millions love to engage and propel the unparalleled AFFiNE
Millions love to engage and
propel the unparalleled
AFFiNE
Dan Charles
CEO - The Keyman Group
Really impressed with how
AFFiNE
is able to streamline our team's workflow and improve productivity. Switch between different modes to write, draw, and plan all in one place and with data security which we are most concerned about. It makes everything easy.
Orange-Cheng
Product manager of the TATDOD Space
Extremely impressed with the quality and capabilities of
AFFiNE
, particularly its simple and intuitive interface. The attention to detail that has been put into every aspect of the product, from its design to its functionality, is truly exceptional. The product's innovative features and capabilities are sure to make a significant impact in the industry, providing customers with a seamless and user-friendly experience.
Maestro
Graphic Designer
With
AFFiNE
's whiteboard feature, I sketch, doodle, and visualize ideas collaboratively in real time. It's an endless canvas for our creativity, allowing us to refine our projects to perfection. The Kanban boards complement our artistic process, ensuring impeccable organization and project tracking.
TinsFox
Front-end Developer
AFFiNE
is by far the best open-source community I’ve come across. Open, inclusive and user-first. At the same time,
AFFiNE
is also a great product. Being open source means more possibilities and more exciting things can be created.
Eliot
Student
AFFiNE
is an open source that is close to its community and filled with useful features. I use edgeless mode to connect all my knowledge to a single page.
Summer123
The Founder of a fashion brand
AFFiNE
's Kanban project management simplifies my hectic workload. Easy task management feels like a personal assistant. Yet, the standout is the whiteboard, streamlining brainstorming, project planning, and workflow visualization.
Joanna
Marketing Manager
AFFiNE
revolutionizes our creative collaboration. Kanban boards effortlessly manage tasks and campaigns. The whiteboard sparks innovation for marketing strategies and content planning, making
AFFiNE
a vital tool for our creative team.
Ragma.TP
Project manager of Tiktok
I'm thrilled with how effortless it was to set up workspaces, arrange pages, and collaborate with my team members in real-time.
AFFiNE
just makes everything easy, streamlines our workflow and boosts our productivity.
Mattias
Student
I've been looking for an open-source note-taking solution for ages now and
AFFiNE
is the first to support all the features I need -- and it even manages to do this while being absolutely beautiful!
AFFiNE
is very feature rich and the synchronization is also awesome.
BusyBee
Full-time Mom
Being a working mom with a hectic schedule,
AFFiNE
is my ultimate lifesaver. Its Kanban boards help me manage household tasks, kids' activities, and work projects with ease. Whether it's organizing chores, tracking school events, or managing deadlines,
AFFiNE
's Kanban feature keeps me on top of it all.
Alice
Student from KCL
One feature I particularly appreciate is the ability to seamlessly switch from typing to handwriting, adding a touch of elegance and versatility to my work.
PanicN3xus
User
AFFiNE
is an exceptional project that elevates note-making to a whole new level. I am highly impressed by the number of features that it brings to the table. Having tried several other open-source note-making software, I can confidently say that
AFFiNE
is the best.
Dynamo
Freelancer
AFFiNE
's Kanban boards are my go-to for life organization, promoting discipline, and habit consistency. I outline goals, plan, and track progress, be it fitness or reading challenges. It's my trusted tool for a fulfilling, disciplined life.
Write Smarter, Work Better with AFFiNE
Write Smarter, Work Better with AFFiNE
Explore the features today, collaborate tomorrow.
Desktop App
Download App
Download App
Mobile App
iOS App
iOS App
Android App
Android App
logo
Company
Terms
Terms
Privacy
Privacy
About Us
About Us
Download
iOS & Android
iOS & Android
Mac & Windows
Mac & Windows
Web Clipper
Web Clipper
Resources
Docs
Docs
Blog
Blog
Templates
Templates
What’s new
What’s new
Community
Community
Timers
Timers
Open Source
AFFiNE
AFFiNE
BlockSuite
BlockSuite
OctoBase
OctoBase
Connect
X (Twitter)
X (Twitter)
GitHub
GitHub
Discord
Discord
YouTube
YouTube
Reddit
Reddit
©2026 Toeverything
·
To Shape, Not to Adapt....
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10201
|
467
|
8
|
2026-05-08T17:11:07.997110+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260267997_m1.jpg...
|
Firefox
|
AFFiNE - All In One KnowledgeOS — Personal
|
1
|
affine.pro
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
logo
Product
Team
Download
Download
Resources
Pricing
Pricing
Get Started
Get Started
github
Stars on GitHub
AFFiNE AI - AI partner to better write, draw & present | Product Hunt
Write, Draw, Plan,All at Once. With AI.
Write,
Draw,
Plan,
All at Once.
With
AI.
AFFiNE is a workspace with fully merged docs, whiteboards and databases.
Get more things done, your creativity isn’t monotone.
Get Started
Get Started
Trusted by people from next-gen startups to established organizations.
Trusted by people from next-gen startups to established organizations.
Consolidate Your Workflow with Ease on a Hyperfused Platform
Consolidate Your Workflow with Ease on a Hyperfused Platform
Say goodbye to the hassle of switchover
Tired of switching between different tools to meet your complex needs?
Stay focused, and unleash your wild creativity with AFFiNE
Your all-in-one KnowledgeOS solution for effortlessly writing, drawing, and planning on a hyper-fused platform.
Privacy-focused, local-first
You are in charge of your own data.
your way to better productivity
your way to better productivity
Build up your content like blocks and let your ideas run wild.
Draw and visualise with ease and creativity
Draw
and visualise with
ease
and
creativity
Visualise your creativity with others. No constraints, limited only by your imagination.
Plan, track, and collaborate efficiently
Plan, track, and collaborate efficiently
Stay on top of your workload and achieve more in less time.
AI partner helps you better write, draw and plan
AI
partner helps you better write, draw and plan
Let you think bigger, create faster, work smarter in anytime, anywhere
learn more
Learn more
Learn more
Ready-to-Use Templates for Any Project
Ready-to-Use Templates for Any Project
Find your ideal template now
Find your ideal template now
Digital Planner
Digital Planner
Story Board
Story Board
Cornell Notes
Cornell Notes
One Pager
One Pager
Checklist
Checklist
Vision Board
Vision Board
Itinerary template
Itinerary template
AFFiNE builds everything in public
AFFiNE builds
everything in public
Open-Source Code for Trust and Collaboration
Open-Source Code for Trust and Collaboration
We foster trust and enable everyone to contribute and enhance AFFiNE for a far wider audience.
toeverything/AFFiNE/issues
Open issues
Closed
Free for individuals, commercial and team usage fees apply.
$$$
Free
$$$
User-Centric Community Engagement
User-Centric Community Engagement
Creating a vibrant space for users to connect, share, and inspire one another.
Join Our Community
Join Our Community
Millions love to engage and propel the unparalleled AFFiNE
Millions love to engage and
propel the unparalleled
AFFiNE
Dan Charles
CEO - The Keyman Group
Orange-Cheng
Product manager of the TATDOD Space
Maestro
Graphic Designer
TinsFox
Front-end Developer
Eliot
Student
Summer123
The Founder of a fashion brand
Joanna
Marketing Manager
Ragma.TP
Project manager of Tiktok
Mattias
Student
BusyBee
Full-time Mom
Alice
Student from KCL
PanicN3xus
User
Dynamo
Freelancer
Write Smarter, Work Better with AFFiNE
Write Smarter, Work Better with AFFiNE
Explore the features today, collaborate tomorrow.
Desktop App
Download App
Download App
Mobile App
iOS App
iOS App
Android App
Android App
logo
Company
Terms
Terms
Privacy
Privacy
About Us
About Us
Download
iOS & Android
iOS & Android
Mac & Windows
Mac & Windows
Web Clipper
Web Clipper
Resources
Docs
Docs
Blog
Blog
Templates
Templates
What’s new
What’s new
Community
Community
Timers
Timers
Open Source
AFFiNE
AFFiNE
BlockSuite
BlockSuite
OctoBase
OctoBase
Connect
X (Twitter)
X (Twitter)
GitHub
GitHub
Discord
Discord
YouTube
YouTube
Reddit
Reddit
©2026 Toeverything
·
To Shape, Not to Adapt.
Transferring data from www.googletagmanager.com…...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.009375,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.03263889,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.05590278,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.079166666,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"logo","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Product","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Team","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Download","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Download","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Resources","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pricing","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pricing","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Get Started","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Get Started","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"github","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Stars on GitHub","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE AI - AI partner to better write, draw & present | Product Hunt","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Write, Draw, Plan,All at Once. With AI.","depth":9,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Write,","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Draw,","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Plan,","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"All at Once.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"With","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AI.","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE is a workspace with fully merged docs, whiteboards and databases.\nGet more things done, your creativity isn’t monotone.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Get Started","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Get Started","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Trusted by people from next-gen startups to established organizations.","depth":8,"bounds":{"left":0.7045139,"top":0.5044444,"width":0.2954861,"height":0.07111111},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trusted by people from next-gen startups to established organizations.","depth":9,"bounds":{"left":0.7114583,"top":0.5061111,"width":0.28854167,"height":0.068333335},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Consolidate Your Workflow with Ease on a Hyperfused Platform","depth":8,"bounds":{"left":0.565625,"top":1.0,"width":0.434375,"height":-0.039444447},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Consolidate Your Workflow with Ease on a Hyperfused Platform","depth":9,"bounds":{"left":0.596875,"top":1.0,"width":0.403125,"height":-0.03888893},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Say goodbye to the hassle of switchover","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tired of switching between different tools to meet your complex needs?","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stay focused, and unleash your wild creativity with AFFiNE","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Your all-in-one KnowledgeOS solution for effortlessly writing, drawing, and planning on a hyper-fused platform.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Privacy-focused, local-first","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You are in charge of your own data.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"your way to better productivity","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"your way to better productivity","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Build up your content like blocks and let your ideas run wild.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Draw and visualise with ease and creativity","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Draw","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and visualise with","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ease","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"creativity","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Visualise your creativity with others. No constraints, limited only by your imagination.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Plan, track, and collaborate efficiently","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Plan, track, and collaborate efficiently","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stay on top of your workload and achieve more in less time.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"AI partner helps you better write, draw and plan","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AI","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"partner helps you better write, draw and plan","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Let you think bigger, create faster, work smarter in anytime, anywhere","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"learn more","depth":8,"on_screen":false,"help_text":"Learn more about AFFiNE AI","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Learn more","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Learn more","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Ready-to-Use Templates for Any Project","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ready-to-Use Templates for Any Project","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Find your ideal template now","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Find your ideal template now","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Digital Planner","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Digital Planner","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Story Board","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Story Board","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Cornell Notes","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Cornell Notes","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"One Pager","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"One Pager","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Checklist","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checklist","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vision Board","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vision Board","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Itinerary template","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Itinerary template","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"AFFiNE builds everything in public","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE builds\neverything in public","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Open-Source Code for Trust and Collaboration","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open-Source Code for Trust and Collaboration","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"We foster trust and enable everyone to contribute and enhance AFFiNE for a far wider audience.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"toeverything/AFFiNE/issues","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open issues","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Closed","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Free for individuals, commercial and team usage fees apply.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$$$","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Free","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$$$","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"User-Centric Community Engagement","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"User-Centric Community Engagement","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Creating a vibrant space for users to connect, share, and inspire one another.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Join Our Community","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Join Our Community","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Millions love to engage and propel the unparalleled AFFiNE","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Millions love to engage and\npropel the unparalleled","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dan Charles","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CEO - The Keyman Group","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Orange-Cheng","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Product manager of the TATDOD Space","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Maestro","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Graphic Designer","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TinsFox","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Front-end Developer","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Eliot","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Student","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Summer123","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Founder of a fashion brand","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Joanna","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Marketing Manager","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ragma.TP","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Project manager of Tiktok","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mattias","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Student","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BusyBee","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Full-time Mom","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Alice","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Student from KCL","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PanicN3xus","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"User","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamo","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Freelancer","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Write Smarter, Work Better with AFFiNE","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Write Smarter, Work Better with AFFiNE","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Explore the features today, collaborate tomorrow.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Desktop App","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Download App","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Download App","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mobile App","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"iOS App","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"iOS App","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Android App","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Android App","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"logo","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Company","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Terms","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Terms","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Privacy","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Privacy","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"About Us","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"About Us","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Download","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"iOS & Android","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"iOS & Android","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Mac & Windows","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Mac & Windows","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Web Clipper","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Web Clipper","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Resources","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Docs","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Docs","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Blog","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Blog","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Templates","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Templates","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"What’s new","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"What’s new","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Community","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Community","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Timers","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Timers","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open Source","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"BlockSuite","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BlockSuite","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"OctoBase","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"OctoBase","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Connect","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"X (Twitter)","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"X (Twitter)","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Discord","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Discord","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"YouTube","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"YouTube","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reddit","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reddit","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"©2026 Toeverything","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"·","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To Shape, Not to Adapt.","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Transferring data from www.googletagmanager.com…","depth":5,"bounds":{"left":0.22083333,"top":0.0,"width":0.19513889,"height":0.015},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-7375414657934748800
|
6499163667826005767
|
click
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
logo
Product
Team
Download
Download
Resources
Pricing
Pricing
Get Started
Get Started
github
Stars on GitHub
AFFiNE AI - AI partner to better write, draw & present | Product Hunt
Write, Draw, Plan,All at Once. With AI.
Write,
Draw,
Plan,
All at Once.
With
AI.
AFFiNE is a workspace with fully merged docs, whiteboards and databases.
Get more things done, your creativity isn’t monotone.
Get Started
Get Started
Trusted by people from next-gen startups to established organizations.
Trusted by people from next-gen startups to established organizations.
Consolidate Your Workflow with Ease on a Hyperfused Platform
Consolidate Your Workflow with Ease on a Hyperfused Platform
Say goodbye to the hassle of switchover
Tired of switching between different tools to meet your complex needs?
Stay focused, and unleash your wild creativity with AFFiNE
Your all-in-one KnowledgeOS solution for effortlessly writing, drawing, and planning on a hyper-fused platform.
Privacy-focused, local-first
You are in charge of your own data.
your way to better productivity
your way to better productivity
Build up your content like blocks and let your ideas run wild.
Draw and visualise with ease and creativity
Draw
and visualise with
ease
and
creativity
Visualise your creativity with others. No constraints, limited only by your imagination.
Plan, track, and collaborate efficiently
Plan, track, and collaborate efficiently
Stay on top of your workload and achieve more in less time.
AI partner helps you better write, draw and plan
AI
partner helps you better write, draw and plan
Let you think bigger, create faster, work smarter in anytime, anywhere
learn more
Learn more
Learn more
Ready-to-Use Templates for Any Project
Ready-to-Use Templates for Any Project
Find your ideal template now
Find your ideal template now
Digital Planner
Digital Planner
Story Board
Story Board
Cornell Notes
Cornell Notes
One Pager
One Pager
Checklist
Checklist
Vision Board
Vision Board
Itinerary template
Itinerary template
AFFiNE builds everything in public
AFFiNE builds
everything in public
Open-Source Code for Trust and Collaboration
Open-Source Code for Trust and Collaboration
We foster trust and enable everyone to contribute and enhance AFFiNE for a far wider audience.
toeverything/AFFiNE/issues
Open issues
Closed
Free for individuals, commercial and team usage fees apply.
$$$
Free
$$$
User-Centric Community Engagement
User-Centric Community Engagement
Creating a vibrant space for users to connect, share, and inspire one another.
Join Our Community
Join Our Community
Millions love to engage and propel the unparalleled AFFiNE
Millions love to engage and
propel the unparalleled
AFFiNE
Dan Charles
CEO - The Keyman Group
Orange-Cheng
Product manager of the TATDOD Space
Maestro
Graphic Designer
TinsFox
Front-end Developer
Eliot
Student
Summer123
The Founder of a fashion brand
Joanna
Marketing Manager
Ragma.TP
Project manager of Tiktok
Mattias
Student
BusyBee
Full-time Mom
Alice
Student from KCL
PanicN3xus
User
Dynamo
Freelancer
Write Smarter, Work Better with AFFiNE
Write Smarter, Work Better with AFFiNE
Explore the features today, collaborate tomorrow.
Desktop App
Download App
Download App
Mobile App
iOS App
iOS App
Android App
Android App
logo
Company
Terms
Terms
Privacy
Privacy
About Us
About Us
Download
iOS & Android
iOS & Android
Mac & Windows
Mac & Windows
Web Clipper
Web Clipper
Resources
Docs
Docs
Blog
Blog
Templates
Templates
What’s new
What’s new
Community
Community
Timers
Timers
Open Source
AFFiNE
AFFiNE
BlockSuite
BlockSuite
OctoBase
OctoBase
Connect
X (Twitter)
X (Twitter)
GitHub
GitHub
Discord
Discord
YouTube
YouTube
Reddit
Reddit
©2026 Toeverything
·
To Shape, Not to Adapt.
Transferring data from www.googletagmanager.com…...
|
10198
|
NULL
|
NULL
|
NULL
|
|
10200
|
468
|
8
|
2026-05-08T17:11:07.912216+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260267912_m2.jpg...
|
Firefox
|
Personal — Mozilla Firefox
|
1
|
affine.pro
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
affine.pro/
affine.pro/
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Transferring data from api.producthunt.com…...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"bounds":{"left":0.26097074,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"bounds":{"left":0.27426863,"top":0.09577015,"width":0.03025266,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"bounds":{"left":0.26097074,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"bounds":{"left":0.27426863,"top":0.12849163,"width":0.05069814,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.26097074,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.27426863,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.26097074,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.27426863,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.26097074,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.27426863,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.26097074,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.27426863,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"bounds":{"left":0.26097074,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"bounds":{"left":0.27426863,"top":0.32482043,"width":0.105884306,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"affine.pro/","depth":4,"bounds":{"left":0.26097074,"top":0.3463687,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"affine.pro/","depth":5,"bounds":{"left":0.27426863,"top":0.3575419,"width":0.017952127,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.36236703,"top":0.35355148,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.26379654,"top":0.38068634,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.26379654,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.27476728,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.28590426,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.29704124,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.3081782,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Transferring data from api.producthunt.com…","depth":5,"bounds":{"left":0.37599733,"top":0.9876297,"width":0.079288565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
7661100180896472024
|
-687781669777631477
|
click
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
affine.pro/
affine.pro/
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Transferring data from api.producthunt.com…...
|
10199
|
NULL
|
NULL
|
NULL
|
|
10199
|
468
|
7
|
2026-05-08T17:11:03.873034+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260263873_m2.jpg...
|
Firefox
|
affine mac - Google Search — Personal
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Ask Google Gemini
Pull requests · screenpipe/scree Ask Google Gemini
Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
affine mac - Google Search
affine mac - Google Search
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to main content
Skip to main content
Accessibility help
Accessibility help
Accessibility feedback
Accessibility feedback
Go to Google Home
affine mac
affine mac
Clear
Search by voice
Search by image
Search
affine api
affine
api
affine plugins
affine
plugins
affine ios
affine
ios
affine ipad
affine
ipad
affine download
affine
download
affine apk
affine
apk
affine ai
affine
ai
affine web
affine
web
Report inappropriate predictions
Report inappropriate predictions
Google apps
Google Account: Lukáš Koválik ([EMAIL])
AI Mode
AI Mode
All
All
Images
Images
Videos
Videos
Forums
Forums
News
News
Short videos
Short videos
More filters
More
Tools
Tools
Search Results
Search Results
Web results
Web results
Download AFFiNE - Offline Notes, Whiteboards, and Local- ... AFFiNE https://affine.pro › download
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
AFFiNE
https://affine.pro
› download
About this result
Download AFFiNE
for offline docs, visual whiteboards, local-first storage, and desktop productivity across macOS, Windows, Linux, iOS, and Android.
AFFiNE - All In One KnowledgeOS AFFiNE https://affine.pro
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
AFFiNE
https://affine.pro
About this result
AFFiNE
is an open-source, privacy-focused workspace that combines docs, whiteboards, and databases. A free Notion & Miro alternative for individuals and ...
Notes,Whiteboard & AI - AFFiNE - App Store - Apple Apple https://apps.apple.com › app › notes-whiteboard-ai-affine
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Apple
https://apps.apple.com
› app › notes-whiteboard-ai-affine
About this result
Think visually, work smarter.
AFFiNE merges an infinite whiteboard with powerful notes, docs, tasks, and AI
. Convert ideas to text instantly and manage ...
toeverything/AFFiNE: There can be more than Notion and ... GitHub https://github.com › toeverything › affine
toeverything/AFFiNE: There can be more than Notion and ...
toeverything/AFFiNE: There can be more than Notion and ...
GitHub
https://github.com
› toeverything › affine
About this result
AFFiNE
is an open-source, all-in-one workspace and an operating system for all the building blocks that assemble your knowledge base and much more -- wiki, ...
AFFiNE for Mac - Download it from Uptodown for free Uptodown https://affine.en.uptodown.com › Mac › Apps › Business
AFFiNE for Mac - Download it from Uptodown for free
AFFiNE for Mac - Download it from Uptodown for free
Uptodown
https://affine.en.uptodown.com
› Mac › Apps › Business
About this result
AFFiNE is a free and open-source app
that lets you create and manage a knowledge base adaptable to almost any purpose. You can use it as a personal journal, ...
Maintaining Peak Mac Performance for Efficient ... AFFiNE https://affine.pro › Blog
Maintaining Peak Mac Performance for Efficient ...
Maintaining Peak Mac Performance for Efficient ...
AFFiNE
https://affine.pro
› Blog
About this result
Dec 26, 2024
—
Affine contains a large library of templates, intuitive canvas and UX design
. It easily integrates with other platforms to boost performance and ...
affine Homebrew Formulae https://formulae.brew.sh › cask › affine
affine
affine
Homebrew Formulae
https://formulae.brew.sh
› cask › affine
About this result
affine
. Install command: brew install --cask affine. Name: AFFiNE ... Requirements: macOS >= 12. Versions: Intel, tahoe, 0.26.3. sequoia, 0.26.3. sonoma ...
AFFiNE for Mac - Download Softonic https://affine.en.softonic.com › Mac › Productivity
AFFiNE for Mac - Download
AFFiNE for Mac - Download
Softonic
https://affine.en.softonic.com
› Mac › Productivity
About this result
Mar 12, 2026
—
AFFiNE is a free software application designed for Mac users
, focusing on enhancing business and productivity workflows. This program provides a ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ... AFFiNE https://affine.pro › pricing
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE
https://affine.pro
› pricing
About this result
$8.9 / month billed annually.
Learn about AFFiNE AI
. Write with you. Create quality content from sentences to articles on topics you need.
AFFiNE is the Next-Gen Knowledge Base to Replace ... Reddit · r/selfhosted 20+ comments · 3 years ago
AFFiNE is the Next-Gen Knowledge Base to Replace ...
AFFiNE is the Next-Gen Knowledge Base to Replace ...
Reddit · r/selfhosted
20+ comments · 3 years ago
About this result
AFFiNE
is the Next-Gen Knowledge Base to Replace Notion & Miro. Open-source, privacy-first, and always free. Built with Typescript/React/Rust.
People also ask
People also ask
What is AFFiNE used for?
What is AFFiNE used for?
Is AFFiNE fully open-source?
Is AFFiNE fully open-source?
How to run AFFiNE locally?
How to run AFFiNE locally?
What is the difference between Docmost and AFFiNE?
What is the difference between Docmost and AFFiNE?
People also search for
People also search for
Affine mac free download
Affine mac
free download
AFFiNE API
AFFiNE
API
AFFiNE plugins
AFFiNE
plugins
AFFiNE iOS
AFFiNE
iOS
AFFiNE iPad
AFFiNE
iPad
AFFiNE download
AFFiNE
download
AFFiNE APK
AFFiNE
APK
AFFiNE AI
AFFiNE
AI
Page navigation
Page navigation
1
Page 2
2
Page 3
3
Page 4
4
Page 5
5
Page 6
6
Page 7
7
Page 8
8
Page 9
9
Page 10
10
Next
Next
Next
Footer links
Footer links
Results are personalised
-
Try without personalisation
Try without personalisation
Bulgaria
Manastirski Livadi, Sofia - Based on your places (Home)
Manastirski Livadi, Sofia
-
Based on your places (Home)
-
Update location
Help
Help
Send feedback
Send feedback
Privacy
Privacy
Terms
Terms...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Ask Google Gemini","depth":4,"bounds":{"left":0.4850399,"top":0.090183556,"width":0.011303191,"height":0.027134877},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"bounds":{"left":0.26097074,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"bounds":{"left":0.27426863,"top":0.09577015,"width":0.03025266,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"bounds":{"left":0.26097074,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"bounds":{"left":0.27426863,"top":0.12849163,"width":0.05069814,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.26097074,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.27426863,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.26097074,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.27426863,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.26097074,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.27426863,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.26097074,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.27426863,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"bounds":{"left":0.26097074,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"bounds":{"left":0.27426863,"top":0.32482043,"width":0.105884306,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"affine mac - Google Search","depth":4,"bounds":{"left":0.26097074,"top":0.3463687,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"affine mac - Google Search","depth":5,"bounds":{"left":0.27426863,"top":0.3575419,"width":0.047539894,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.36236703,"top":0.35355148,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.26379654,"top":0.38068634,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.26379654,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.27476728,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.28590426,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.29704124,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.3081782,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to main content","depth":7,"bounds":{"left":0.37832448,"top":0.09577015,"width":0.03656915,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to main content","depth":8,"bounds":{"left":0.38380983,"top":0.09896249,"width":0.025598405,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Accessibility help","depth":7,"bounds":{"left":0.37832448,"top":0.09577015,"width":0.03656915,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Accessibility help","depth":8,"bounds":{"left":0.38397607,"top":0.09896249,"width":0.025265958,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Accessibility feedback","depth":7,"bounds":{"left":0.37832448,"top":0.11811652,"width":0.03656915,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Accessibility feedback","depth":8,"bounds":{"left":0.38397607,"top":0.121308856,"width":0.025265958,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to Google Home","depth":11,"bounds":{"left":0.39926863,"top":0.07821229,"width":0.030585106,"height":0.026735835},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"affine mac","depth":10,"bounds":{"left":0.45146278,"top":0.07102953,"width":0.21875,"height":0.03990423},"on_screen":true,"value":"affine mac","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"affine mac","depth":11,"bounds":{"left":0.45146278,"top":0.0830008,"width":0.025598405,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Clear","depth":10,"bounds":{"left":0.67021275,"top":0.07102953,"width":0.015957447,"height":0.03990423},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search by voice","depth":10,"bounds":{"left":0.6878325,"top":0.08140463,"width":0.013297873,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search by image","depth":10,"bounds":{"left":0.70113033,"top":0.08140463,"width":0.013297873,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search","depth":10,"bounds":{"left":0.71575797,"top":0.07102953,"width":0.01462766,"height":0.03990423},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"affine api","depth":14,"bounds":{"left":0.45146278,"top":0.11971269,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.11971269,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"api","depth":16,"bounds":{"left":0.46542552,"top":0.11971269,"width":0.00930851,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine plugins","depth":14,"bounds":{"left":0.45146278,"top":0.14565043,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.14565043,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"plugins","depth":16,"bounds":{"left":0.46542552,"top":0.14565043,"width":0.020113032,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine ios","depth":14,"bounds":{"left":0.45146278,"top":0.17158818,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.17158818,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ios","depth":16,"bounds":{"left":0.46542552,"top":0.17158818,"width":0.00880984,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine ipad","depth":14,"bounds":{"left":0.45146278,"top":0.19752593,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.19752593,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ipad","depth":16,"bounds":{"left":0.46542552,"top":0.19752593,"width":0.012632979,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine download","depth":14,"bounds":{"left":0.45146278,"top":0.22346368,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.22346368,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"download","depth":16,"bounds":{"left":0.46542552,"top":0.22346368,"width":0.026595745,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine apk","depth":14,"bounds":{"left":0.45146278,"top":0.24940144,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.24940144,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"apk","depth":16,"bounds":{"left":0.46542552,"top":0.24940144,"width":0.010804521,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine ai","depth":14,"bounds":{"left":0.45146278,"top":0.2753392,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.2753392,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ai","depth":16,"bounds":{"left":0.46542552,"top":0.2753392,"width":0.005984043,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine web","depth":14,"bounds":{"left":0.45146278,"top":0.30127692,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.30127692,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"web","depth":16,"bounds":{"left":0.46542552,"top":0.30127692,"width":0.012134309,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Report inappropriate predictions","depth":11,"bounds":{"left":0.67004657,"top":0.3320032,"width":0.054022606,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Report inappropriate predictions","depth":13,"bounds":{"left":0.67004657,"top":0.3320032,"width":0.054022606,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Google apps","depth":9,"bounds":{"left":0.9640958,"top":0.075019956,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Google Account: Lukáš Koválik (kovaliklukas@gmail.com)","depth":8,"bounds":{"left":0.9800532,"top":0.075019956,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"AI Mode","depth":17,"bounds":{"left":0.44714096,"top":0.11971269,"width":0.025930852,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI Mode","depth":19,"bounds":{"left":0.45113033,"top":0.13407822,"width":0.017952127,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"All","depth":17,"bounds":{"left":0.4730718,"top":0.11971269,"width":0.013464096,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All","depth":20,"bounds":{"left":0.47706118,"top":0.13407822,"width":0.005485372,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Images","depth":17,"bounds":{"left":0.4865359,"top":0.11971269,"width":0.023769947,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Images","depth":19,"bounds":{"left":0.49052528,"top":0.13407822,"width":0.015791224,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Videos","depth":17,"bounds":{"left":0.5103058,"top":0.11971269,"width":0.022772606,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Videos","depth":19,"bounds":{"left":0.5142952,"top":0.13407822,"width":0.014793883,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Forums","depth":17,"bounds":{"left":0.53307843,"top":0.11971269,"width":0.024268618,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Forums","depth":19,"bounds":{"left":0.53706783,"top":0.13407822,"width":0.016289894,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"News","depth":17,"bounds":{"left":0.55734706,"top":0.11971269,"width":0.019780586,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"News","depth":19,"bounds":{"left":0.56133646,"top":0.13407822,"width":0.011801862,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Short videos","depth":17,"bounds":{"left":0.57712764,"top":0.11971269,"width":0.035738032,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Short videos","depth":19,"bounds":{"left":0.58111703,"top":0.13407822,"width":0.027759308,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More filters","depth":17,"bounds":{"left":0.6128657,"top":0.11971269,"width":0.025099734,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":20,"bounds":{"left":0.616855,"top":0.13407822,"width":0.011136968,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Tools","depth":16,"bounds":{"left":0.63796544,"top":0.11971269,"width":0.02543218,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Tools","depth":18,"bounds":{"left":0.6419548,"top":0.13407822,"width":0.011469414,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Search Results","depth":8,"bounds":{"left":0.37466756,"top":0.15802075,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Search Results","depth":9,"bounds":{"left":0.37466756,"top":0.15841979,"width":0.03158245,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Web results","depth":15,"bounds":{"left":0.45113033,"top":0.19592977,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Web results","depth":16,"bounds":{"left":0.45113033,"top":0.19513169,"width":0.03939495,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Download AFFiNE - Offline Notes, Whiteboards, and Local- ... AFFiNE https://affine.pro › download","depth":16,"bounds":{"left":0.45113033,"top":0.18754987,"width":0.1810173,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Download AFFiNE - Offline Notes, Whiteboards, and Local- ...","depth":17,"bounds":{"left":0.45113033,"top":0.2122905,"width":0.1810173,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Download AFFiNE - Offline Notes, Whiteboards, and Local- ...","depth":18,"bounds":{"left":0.45113033,"top":0.21667998,"width":0.1810173,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"bounds":{"left":0.4644282,"top":0.18355946,"width":0.016289894,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"bounds":{"left":0.4644282,"top":0.19952115,"width":0.028590426,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› download","depth":22,"bounds":{"left":0.49301863,"top":0.19952115,"width":0.020611702,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.5162899,"top":0.1963288,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Download AFFiNE","depth":17,"bounds":{"left":0.45113033,"top":0.24181964,"width":0.040392287,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"for offline docs, visual whiteboards, local-first storage, and desktop productivity across macOS, Windows, Linux, iOS, and Android.","depth":16,"bounds":{"left":0.45113033,"top":0.24181964,"width":0.20345744,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE - All In One KnowledgeOS AFFiNE https://affine.pro","depth":16,"bounds":{"left":0.45113033,"top":0.30407023,"width":0.10006649,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE - All In One KnowledgeOS","depth":17,"bounds":{"left":0.45113033,"top":0.32881084,"width":0.10006649,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":18,"bounds":{"left":0.45113033,"top":0.3332003,"width":0.10006649,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"bounds":{"left":0.4644282,"top":0.30007982,"width":0.016289894,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"bounds":{"left":0.4644282,"top":0.3160415,"width":0.028590426,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.4956782,"top":0.31284916,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":17,"bounds":{"left":0.45113033,"top":0.35834,"width":0.016788565,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is an open-source, privacy-focused workspace that combines docs, whiteboards, and databases. A free Notion & Miro alternative for individuals and ...","depth":16,"bounds":{"left":0.45113033,"top":0.35834,"width":0.1931516,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Notes,Whiteboard & AI - AFFiNE - App Store - Apple Apple https://apps.apple.com › app › notes-whiteboard-ai-affine","depth":16,"bounds":{"left":0.45113033,"top":0.4253791,"width":0.1534242,"height":0.03471668},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Notes,Whiteboard & AI - AFFiNE - App Store - Apple","depth":17,"bounds":{"left":0.45113033,"top":0.44533122,"width":0.1534242,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Notes,Whiteboard & AI - AFFiNE - App Store - Apple","depth":18,"bounds":{"left":0.45113033,"top":0.44972068,"width":0.1534242,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Apple","depth":21,"bounds":{"left":0.4644282,"top":0.41660017,"width":0.011968086,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://apps.apple.com","depth":21,"bounds":{"left":0.4644282,"top":0.43256184,"width":0.040059842,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› app › notes-whiteboard-ai-affine","depth":22,"bounds":{"left":0.50448805,"top":0.43256184,"width":0.059840426,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.56632316,"top":0.4293695,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Think visually, work smarter.","depth":16,"bounds":{"left":0.45113033,"top":0.47486034,"width":0.059341755,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE merges an infinite whiteboard with powerful notes, docs, tasks, and AI","depth":17,"bounds":{"left":0.45113033,"top":0.47486034,"width":0.203125,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". Convert ideas to text instantly and manage ...","depth":16,"bounds":{"left":0.47988698,"top":0.4924182,"width":0.09591091,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"toeverything/AFFiNE: There can be more than Notion and ... GitHub https://github.com › toeverything › affine","depth":16,"bounds":{"left":0.45113033,"top":0.5371109,"width":0.17569813,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"toeverything/AFFiNE: There can be more than Notion and ...","depth":17,"bounds":{"left":0.45113033,"top":0.56185156,"width":0.17569813,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"toeverything/AFFiNE: There can be more than Notion and ...","depth":18,"bounds":{"left":0.45113033,"top":0.566241,"width":0.17569813,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"GitHub","depth":21,"bounds":{"left":0.4644282,"top":0.5331205,"width":0.014461436,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://github.com","depth":21,"bounds":{"left":0.4644282,"top":0.5490822,"width":0.031416222,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› toeverything › affine","depth":22,"bounds":{"left":0.49584442,"top":0.5490822,"width":0.03856383,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.53706783,"top":0.54588985,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":17,"bounds":{"left":0.45113033,"top":0.5913807,"width":0.016788565,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is an open-source, all-in-one workspace and an operating system for all the building blocks that assemble your knowledge base and much more -- wiki, ...","depth":16,"bounds":{"left":0.45113033,"top":0.5913807,"width":0.21392952,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE for Mac - Download it from Uptodown for free Uptodown https://affine.en.uptodown.com › Mac › Apps › Business","depth":16,"bounds":{"left":0.45113033,"top":0.65363127,"width":0.15974069,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE for Mac - Download it from Uptodown for free","depth":17,"bounds":{"left":0.45113033,"top":0.6783719,"width":0.15974069,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE for Mac - Download it from Uptodown for free","depth":18,"bounds":{"left":0.45113033,"top":0.6827614,"width":0.15974069,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Uptodown","depth":21,"bounds":{"left":0.4644282,"top":0.64964086,"width":0.020944148,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.en.uptodown.com","depth":21,"bounds":{"left":0.4644282,"top":0.66560256,"width":0.05418883,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› Mac › Apps › Business","depth":22,"bounds":{"left":0.51861703,"top":0.66560256,"width":0.043550532,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.56482714,"top":0.6624102,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE is a free and open-source app","depth":17,"bounds":{"left":0.45113033,"top":0.70790106,"width":0.084109046,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"that lets you create and manage a knowledge base adaptable to almost any purpose. You can use it as a personal journal, ...","depth":16,"bounds":{"left":0.45113033,"top":0.70790106,"width":0.2122673,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Maintaining Peak Mac Performance for Efficient ... AFFiNE https://affine.pro › Blog","depth":16,"bounds":{"left":0.45113033,"top":0.7701516,"width":0.14777261,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Maintaining Peak Mac Performance for Efficient ...","depth":17,"bounds":{"left":0.45113033,"top":0.79489225,"width":0.14777261,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Maintaining Peak Mac Performance for Efficient ...","depth":18,"bounds":{"left":0.45113033,"top":0.7992817,"width":0.14777261,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"bounds":{"left":0.4644282,"top":0.7661612,"width":0.016289894,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"bounds":{"left":0.4644282,"top":0.7821229,"width":0.028590426,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› Blog","depth":22,"bounds":{"left":0.49301863,"top":0.7821229,"width":0.011469414,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.5071476,"top":0.77893054,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dec 26, 2024","depth":16,"bounds":{"left":0.45113033,"top":0.8244214,"width":0.027759308,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":16,"bounds":{"left":0.4788896,"top":0.8244214,"width":0.0071476065,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Affine contains a large library of templates, intuitive canvas and UX design","depth":17,"bounds":{"left":0.48603722,"top":0.8244214,"width":0.16522606,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". It easily integrates with other platforms to boost performance and ...","depth":16,"bounds":{"left":0.45113033,"top":0.8244214,"width":0.2052859,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"affine Homebrew Formulae https://formulae.brew.sh › cask › affine","depth":16,"bounds":{"left":0.45113033,"top":0.8914605,"width":0.08061835,"height":0.03471668},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"affine","depth":17,"bounds":{"left":0.45113033,"top":0.9114126,"width":0.017287234,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":18,"bounds":{"left":0.45113033,"top":0.91580206,"width":0.017287234,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Homebrew Formulae","depth":21,"bounds":{"left":0.4644282,"top":0.88268155,"width":0.04338431,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://formulae.brew.sh","depth":21,"bounds":{"left":0.4644282,"top":0.89864326,"width":0.042386968,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› cask › affine","depth":22,"bounds":{"left":0.50681514,"top":0.89864326,"width":0.024933511,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.5337433,"top":0.8954509,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"affine","depth":17,"bounds":{"left":0.45113033,"top":0.94094175,"width":0.012466756,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". Install command: brew install --cask affine. Name: AFFiNE ... Requirements: macOS >= 12. Versions: Intel, tahoe, 0.26.3. sequoia, 0.26.3. sonoma ...","depth":16,"bounds":{"left":0.45113033,"top":0.94094175,"width":0.203125,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE for Mac - Download Softonic https://affine.en.softonic.com › Mac › Productivity","depth":16,"bounds":{"left":0.45113033,"top":1.0,"width":0.09923537,"height":-0.0031923056},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE for Mac - Download","depth":17,"bounds":{"left":0.45113033,"top":1.0,"width":0.08194814,"height":-0.027933002},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE for Mac - Download","depth":18,"bounds":{"left":0.45113033,"top":1.0,"width":0.08194814,"height":-0.032322407},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Softonic","depth":21,"bounds":{"left":0.4644282,"top":0.9992019,"width":0.016788565,"height":0.0007981062},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.en.softonic.com","depth":21,"bounds":{"left":0.4644282,"top":1.0,"width":0.05069814,"height":-0.01516366},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› Mac › Productivity","depth":22,"bounds":{"left":0.51512635,"top":1.0,"width":0.03523936,"height":-0.01516366},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.55302525,"top":1.0,"width":0.00930851,"height":-0.011971235},"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Mar 12, 2026","depth":16,"bounds":{"left":0.45113033,"top":1.0,"width":0.027426861,"height":-0.057462096},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":16,"bounds":{"left":0.47855717,"top":1.0,"width":0.0071476065,"height":-0.057462096},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE is a free software application designed for Mac users","depth":17,"bounds":{"left":0.48570478,"top":1.0,"width":0.13530585,"height":-0.057462096},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", focusing on enhancing business and productivity workflows. This program provides a ...","depth":16,"bounds":{"left":0.45113033,"top":1.0,"width":0.19630983,"height":-0.057462096},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ... AFFiNE https://affine.pro › pricing","depth":16,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...","depth":17,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› pricing","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"$8.9 / month billed annually.","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Learn about AFFiNE AI","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". Write with you. Create quality content from sentences to articles on topics you need.","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE is the Next-Gen Knowledge Base to Replace ... Reddit · r/selfhosted 20+ comments · 3 years ago","depth":16,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE is the Next-Gen Knowledge Base to Replace ...","depth":17,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE is the Next-Gen Knowledge Base to Replace ...","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Reddit · r/selfhosted","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20+ comments · 3 years ago","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is the Next-Gen Knowledge Base to Replace Notion & Miro. Open-source, privacy-first, and always free. Built with Typescript/React/Rust.","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"People also ask","depth":16,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"People also ask","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"What is AFFiNE used for?","depth":19,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"What is AFFiNE used for?","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Is AFFiNE fully open-source?","depth":19,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Is AFFiNE fully open-source?","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"How to run AFFiNE locally?","depth":19,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"How to run AFFiNE locally?","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"What is the difference between Docmost and AFFiNE?","depth":19,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"What is the difference between Docmost and AFFiNE?","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"People also search for","depth":14,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"People also search for","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Affine mac free download","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Affine mac","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"free download","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE API","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"API","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE plugins","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"plugins","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE iOS","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"iOS","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE iPad","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"iPad","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE download","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"download","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE APK","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"APK","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE AI","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AI","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Page navigation","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Page navigation","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 2","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 3","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 4","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 5","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 6","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"6","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 7","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 8","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 9","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 10","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Next","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"Next","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Next","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Footer links","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Footer links","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Results are personalised","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Try without personalisation","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Try without personalisation","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bulgaria","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Manastirski Livadi, Sofia - Based on your places (Home)","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Manastirski Livadi, Sofia","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Based on your places (Home)","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Update location","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Help","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Send feedback","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send feedback","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Privacy","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Privacy","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Terms","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Terms","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
1527475732929063830
|
-7551337041370017825
|
click
|
accessibility
|
NULL
|
Ask Google Gemini
Pull requests · screenpipe/scree Ask Google Gemini
Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
affine mac - Google Search
affine mac - Google Search
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to main content
Skip to main content
Accessibility help
Accessibility help
Accessibility feedback
Accessibility feedback
Go to Google Home
affine mac
affine mac
Clear
Search by voice
Search by image
Search
affine api
affine
api
affine plugins
affine
plugins
affine ios
affine
ios
affine ipad
affine
ipad
affine download
affine
download
affine apk
affine
apk
affine ai
affine
ai
affine web
affine
web
Report inappropriate predictions
Report inappropriate predictions
Google apps
Google Account: Lukáš Koválik ([EMAIL])
AI Mode
AI Mode
All
All
Images
Images
Videos
Videos
Forums
Forums
News
News
Short videos
Short videos
More filters
More
Tools
Tools
Search Results
Search Results
Web results
Web results
Download AFFiNE - Offline Notes, Whiteboards, and Local- ... AFFiNE https://affine.pro › download
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
AFFiNE
https://affine.pro
› download
About this result
Download AFFiNE
for offline docs, visual whiteboards, local-first storage, and desktop productivity across macOS, Windows, Linux, iOS, and Android.
AFFiNE - All In One KnowledgeOS AFFiNE https://affine.pro
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
AFFiNE
https://affine.pro
About this result
AFFiNE
is an open-source, privacy-focused workspace that combines docs, whiteboards, and databases. A free Notion & Miro alternative for individuals and ...
Notes,Whiteboard & AI - AFFiNE - App Store - Apple Apple https://apps.apple.com › app › notes-whiteboard-ai-affine
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Apple
https://apps.apple.com
› app › notes-whiteboard-ai-affine
About this result
Think visually, work smarter.
AFFiNE merges an infinite whiteboard with powerful notes, docs, tasks, and AI
. Convert ideas to text instantly and manage ...
toeverything/AFFiNE: There can be more than Notion and ... GitHub https://github.com › toeverything › affine
toeverything/AFFiNE: There can be more than Notion and ...
toeverything/AFFiNE: There can be more than Notion and ...
GitHub
https://github.com
› toeverything › affine
About this result
AFFiNE
is an open-source, all-in-one workspace and an operating system for all the building blocks that assemble your knowledge base and much more -- wiki, ...
AFFiNE for Mac - Download it from Uptodown for free Uptodown https://affine.en.uptodown.com › Mac › Apps › Business
AFFiNE for Mac - Download it from Uptodown for free
AFFiNE for Mac - Download it from Uptodown for free
Uptodown
https://affine.en.uptodown.com
› Mac › Apps › Business
About this result
AFFiNE is a free and open-source app
that lets you create and manage a knowledge base adaptable to almost any purpose. You can use it as a personal journal, ...
Maintaining Peak Mac Performance for Efficient ... AFFiNE https://affine.pro › Blog
Maintaining Peak Mac Performance for Efficient ...
Maintaining Peak Mac Performance for Efficient ...
AFFiNE
https://affine.pro
› Blog
About this result
Dec 26, 2024
—
Affine contains a large library of templates, intuitive canvas and UX design
. It easily integrates with other platforms to boost performance and ...
affine Homebrew Formulae https://formulae.brew.sh › cask › affine
affine
affine
Homebrew Formulae
https://formulae.brew.sh
› cask › affine
About this result
affine
. Install command: brew install --cask affine. Name: AFFiNE ... Requirements: macOS >= 12. Versions: Intel, tahoe, 0.26.3. sequoia, 0.26.3. sonoma ...
AFFiNE for Mac - Download Softonic https://affine.en.softonic.com › Mac › Productivity
AFFiNE for Mac - Download
AFFiNE for Mac - Download
Softonic
https://affine.en.softonic.com
› Mac › Productivity
About this result
Mar 12, 2026
—
AFFiNE is a free software application designed for Mac users
, focusing on enhancing business and productivity workflows. This program provides a ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ... AFFiNE https://affine.pro › pricing
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE
https://affine.pro
› pricing
About this result
$8.9 / month billed annually.
Learn about AFFiNE AI
. Write with you. Create quality content from sentences to articles on topics you need.
AFFiNE is the Next-Gen Knowledge Base to Replace ... Reddit · r/selfhosted 20+ comments · 3 years ago
AFFiNE is the Next-Gen Knowledge Base to Replace ...
AFFiNE is the Next-Gen Knowledge Base to Replace ...
Reddit · r/selfhosted
20+ comments · 3 years ago
About this result
AFFiNE
is the Next-Gen Knowledge Base to Replace Notion & Miro. Open-source, privacy-first, and always free. Built with Typescript/React/Rust.
People also ask
People also ask
What is AFFiNE used for?
What is AFFiNE used for?
Is AFFiNE fully open-source?
Is AFFiNE fully open-source?
How to run AFFiNE locally?
How to run AFFiNE locally?
What is the difference between Docmost and AFFiNE?
What is the difference between Docmost and AFFiNE?
People also search for
People also search for
Affine mac free download
Affine mac
free download
AFFiNE API
AFFiNE
API
AFFiNE plugins
AFFiNE
plugins
AFFiNE iOS
AFFiNE
iOS
AFFiNE iPad
AFFiNE
iPad
AFFiNE download
AFFiNE
download
AFFiNE APK
AFFiNE
APK
AFFiNE AI
AFFiNE
AI
Page navigation
Page navigation
1
Page 2
2
Page 3
3
Page 4
4
Page 5
5
Page 6
6
Page 7
7
Page 8
8
Page 9
9
Page 10
10
Next
Next
Next
Footer links
Footer links
Results are personalised
-
Try without personalisation
Try without personalisation
Bulgaria
Manastirski Livadi, Sofia - Based on your places (Home)
Manastirski Livadi, Sofia
-
Based on your places (Home)
-
Update location
Help
Help
Send feedback
Send feedback
Privacy
Privacy
Terms
Terms...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10198
|
467
|
7
|
2026-05-08T17:11:03.523798+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260263523_m1.jpg...
|
Firefox
|
affine mac - Google Search — Personal
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Ask Google Gemini
Pull requests · screenpipe/scree Ask Google Gemini
Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
affine mac - Google Search
affine mac - Google Search
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to main content
Skip to main content
Accessibility help
Accessibility help
Accessibility feedback
Accessibility feedback
Go to Google Home
affine mac
affine mac
Clear
Search by voice
Search by image
Search
affine api
affine
api
affine plugins
affine
plugins
affine ios
affine
ios
affine ipad
affine
ipad
affine download
affine
download
affine apk
affine
apk
affine ai
affine
ai
affine web
affine
web
Report inappropriate predictions
Report inappropriate predictions
Google apps
Google Account: Lukáš Koválik ([EMAIL])
AI Mode
AI Mode
All
All
Images
Images
Videos
Videos
Forums
Forums
News
News
Short videos
Short videos
More filters
More
Tools
Tools
Search Results
Search Results
Web results
Web results
Download AFFiNE - Offline Notes, Whiteboards, and Local- ... AFFiNE https://affine.pro › download
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
AFFiNE
https://affine.pro
› download
About this result
Download AFFiNE
for offline docs, visual whiteboards, local-first storage, and desktop productivity across macOS, Windows, Linux, iOS, and Android.
AFFiNE - All In One KnowledgeOS AFFiNE https://affine.pro
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
AFFiNE
https://affine.pro
About this result
AFFiNE
is an open-source, privacy-focused workspace that combines docs, whiteboards, and databases. A free Notion & Miro alternative for individuals and ...
Notes,Whiteboard & AI - AFFiNE - App Store - Apple Apple https://apps.apple.com › app › notes-whiteboard-ai-affine
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Apple
https://apps.apple.com
› app › notes-whiteboard-ai-affine
About this result
Think visually, work smarter.
AFFiNE merges an infinite whiteboard with powerful notes, docs, tasks, and AI
. Convert ideas to text instantly and manage ...
toeverything/AFFiNE: There can be more than Notion and ... GitHub https://github.com › toeverything › affine
toeverything/AFFiNE: There can be more than Notion and ...
toeverything/AFFiNE: There can be more than Notion and ...
GitHub
https://github.com
› toeverything › affine
About this result
AFFiNE
is an open-source, all-in-one workspace and an operating system for all the building blocks that assemble your knowledge base and much more -- wiki, ...
AFFiNE for Mac - Download it from Uptodown for free Uptodown https://affine.en.uptodown.com › Mac › Apps › Business
AFFiNE for Mac - Download it from Uptodown for free
AFFiNE for Mac - Download it from Uptodown for free
Uptodown
https://affine.en.uptodown.com
› Mac › Apps › Business
About this result
AFFiNE is a free and open-source app
that lets you create and manage a knowledge base adaptable to almost any purpose. You can use it as a personal journal, ...
Maintaining Peak Mac Performance for Efficient ... AFFiNE https://affine.pro › Blog
Maintaining Peak Mac Performance for Efficient ...
Maintaining Peak Mac Performance for Efficient ...
AFFiNE
https://affine.pro
› Blog
About this result
Dec 26, 2024
—
Affine contains a large library of templates, intuitive canvas and UX design
. It easily integrates with other platforms to boost performance and ...
affine Homebrew Formulae https://formulae.brew.sh › cask › affine
affine
affine
Homebrew Formulae
https://formulae.brew.sh
› cask › affine
About this result
affine
. Install command: brew install --cask affine. Name: AFFiNE ... Requirements: macOS >= 12. Versions: Intel, tahoe, 0.26.3. sequoia, 0.26.3. sonoma ...
AFFiNE for Mac - Download Softonic https://affine.en.softonic.com › Mac › Productivity
AFFiNE for Mac - Download
AFFiNE for Mac - Download
Softonic
https://affine.en.softonic.com
› Mac › Productivity
About this result
Mar 12, 2026
—
AFFiNE is a free software application designed for Mac users
, focusing on enhancing business and productivity workflows. This program provides a ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ... AFFiNE https://affine.pro › pricing
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE
https://affine.pro
› pricing
About this result
$8.9 / month billed annually.
Learn about AFFiNE AI
. Write with you. Create quality content from sentences to articles on topics you need.
AFFiNE is the Next-Gen Knowledge Base to Replace ... Reddit · r/selfhosted 20+ comments · 3 years ago
AFFiNE is the Next-Gen Knowledge Base to Replace ...
AFFiNE is the Next-Gen Knowledge Base to Replace ...
Reddit · r/selfhosted
20+ comments · 3 years ago
About this result
AFFiNE
is the Next-Gen Knowledge Base to Replace Notion & Miro. Open-source, privacy-first, and always free. Built with Typescript/React/Rust.
People also ask
People also ask
What is AFFiNE used for?
What is AFFiNE used for?
Is AFFiNE fully open-source?
Is AFFiNE fully open-source?
How to run AFFiNE locally?
How to run AFFiNE locally?
What is the difference between Docmost and AFFiNE?
What is the difference between Docmost and AFFiNE?
People also search for
People also search for
Affine mac free download
Affine mac
free download
AFFiNE API
AFFiNE
API
AFFiNE plugins
AFFiNE
plugins
AFFiNE iOS
AFFiNE
iOS
AFFiNE iPad
AFFiNE
iPad
AFFiNE download
AFFiNE
download
AFFiNE APK
AFFiNE
APK
AFFiNE AI
AFFiNE
AI
Page navigation
Page navigation
1
Page 2
2
Page 3
3
Page 4
4
Page 5
5
Page 6
6
Page 7
7
Page 8
8
Page 9
9
Page 10
10
Next
Next
Next
Footer links
Footer links
Results are personalised
-
Try without personalisation
Try without personalisation
Bulgaria
Manastirski Livadi, Sofia - Based on your places (Home)
Manastirski Livadi, Sofia
-
Based on your places (Home)
-
Update location
Help
Help
Send feedback
Send feedback
Privacy
Privacy
Terms
Terms...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Ask Google Gemini","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"affine mac - Google Search","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"affine mac - Google Search","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.009375,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.03263889,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.05590278,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.079166666,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to main content","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to main content","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Accessibility help","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Accessibility help","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Accessibility feedback","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Accessibility feedback","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to Google Home","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"affine mac","depth":10,"on_screen":true,"value":"affine mac","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"affine mac","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Clear","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search by voice","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search by image","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"affine api","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"api","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine plugins","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"plugins","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine ios","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ios","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine ipad","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ipad","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine download","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"download","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine apk","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"apk","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine ai","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ai","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine web","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"web","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Report inappropriate predictions","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Report inappropriate predictions","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Google apps","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Google Account: Lukáš Koválik (kovaliklukas@gmail.com)","depth":8,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"AI Mode","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI Mode","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"All","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Images","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Images","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Videos","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Videos","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Forums","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Forums","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"News","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"News","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Short videos","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Short videos","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More filters","depth":17,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Tools","depth":16,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Tools","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Search Results","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Search Results","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Web results","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Web results","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Download AFFiNE - Offline Notes, Whiteboards, and Local- ... AFFiNE https://affine.pro › download","depth":16,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Download AFFiNE - Offline Notes, Whiteboards, and Local- ...","depth":17,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Download AFFiNE - Offline Notes, Whiteboards, and Local- ...","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› download","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Download AFFiNE","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"for offline docs, visual whiteboards, local-first storage, and desktop productivity across macOS, Windows, Linux, iOS, and Android.","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE - All In One KnowledgeOS AFFiNE https://affine.pro","depth":16,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE - All In One KnowledgeOS","depth":17,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is an open-source, privacy-focused workspace that combines docs, whiteboards, and databases. A free Notion & Miro alternative for individuals and ...","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Notes,Whiteboard & AI - AFFiNE - App Store - Apple Apple https://apps.apple.com › app › notes-whiteboard-ai-affine","depth":16,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Notes,Whiteboard & AI - AFFiNE - App Store - Apple","depth":17,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Notes,Whiteboard & AI - AFFiNE - App Store - Apple","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Apple","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://apps.apple.com","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› app › notes-whiteboard-ai-affine","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Think visually, work smarter.","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE merges an infinite whiteboard with powerful notes, docs, tasks, and AI","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". Convert ideas to text instantly and manage ...","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"toeverything/AFFiNE: There can be more than Notion and ... GitHub https://github.com › toeverything › affine","depth":16,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"toeverything/AFFiNE: There can be more than Notion and ...","depth":17,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"toeverything/AFFiNE: There can be more than Notion and ...","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"GitHub","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://github.com","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› toeverything › affine","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is an open-source, all-in-one workspace and an operating system for all the building blocks that assemble your knowledge base and much more -- wiki, ...","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE for Mac - Download it from Uptodown for free Uptodown https://affine.en.uptodown.com › Mac › Apps › Business","depth":16,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE for Mac - Download it from Uptodown for free","depth":17,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE for Mac - Download it from Uptodown for free","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Uptodown","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.en.uptodown.com","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› Mac › Apps › Business","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE is a free and open-source app","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"that lets you create and manage a knowledge base adaptable to almost any purpose. You can use it as a personal journal, ...","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Maintaining Peak Mac Performance for Efficient ... AFFiNE https://affine.pro › Blog","depth":16,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Maintaining Peak Mac Performance for Efficient ...","depth":17,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Maintaining Peak Mac Performance for Efficient ...","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› Blog","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dec 26, 2024","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Affine contains a large library of templates, intuitive canvas and UX design","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". It easily integrates with other platforms to boost performance and ...","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"affine Homebrew Formulae https://formulae.brew.sh › cask › affine","depth":16,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"affine","depth":17,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Homebrew Formulae","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://formulae.brew.sh","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› cask › affine","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"affine","depth":17,"bounds":{"left":0.37777779,"top":0.0,"width":0.026041666,"height":0.017777778},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". Install command: brew install --cask affine. Name: AFFiNE ... Requirements: macOS >= 12. Versions: Intel, tahoe, 0.26.3. sequoia, 0.26.3. sonoma ...","depth":16,"bounds":{"left":0.37777779,"top":0.0,"width":0.42430556,"height":0.04222222},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE for Mac - Download Softonic https://affine.en.softonic.com › Mac › Productivity","depth":16,"bounds":{"left":0.37777779,"top":0.0044444446,"width":0.20729166,"height":0.055},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE for Mac - Download","depth":17,"bounds":{"left":0.37777779,"top":0.03888889,"width":0.17118056,"height":0.034444444},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE for Mac - Download","depth":18,"bounds":{"left":0.37777779,"top":0.045,"width":0.17118056,"height":0.028333334},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Softonic","depth":21,"bounds":{"left":0.40555555,"top":0.0,"width":0.035069443,"height":0.017777778},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.en.softonic.com","depth":21,"bounds":{"left":0.40555555,"top":0.02111111,"width":0.105902776,"height":0.015555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› Mac › Productivity","depth":22,"bounds":{"left":0.51145834,"top":0.02111111,"width":0.07361111,"height":0.015555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.590625,"top":0.016666668,"width":0.019444445,"height":0.022222223},"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Mar 12, 2026","depth":16,"bounds":{"left":0.37777779,"top":0.08,"width":0.057291668,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":16,"bounds":{"left":0.43506944,"top":0.08,"width":0.014930556,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE is a free software application designed for Mac users","depth":17,"bounds":{"left":0.45,"top":0.08,"width":0.28263888,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", focusing on enhancing business and productivity workflows. This program provides a ...","depth":16,"bounds":{"left":0.37777779,"top":0.08,"width":0.41006944,"height":0.04222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ... AFFiNE https://affine.pro › pricing","depth":16,"bounds":{"left":0.37777779,"top":0.16666667,"width":0.3454861,"height":0.055},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...","depth":17,"bounds":{"left":0.37777779,"top":0.20111111,"width":0.3454861,"height":0.034444444},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...","depth":18,"bounds":{"left":0.37777779,"top":0.20722222,"width":0.3454861,"height":0.028333334},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"bounds":{"left":0.40555555,"top":0.16111112,"width":0.034027778,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"bounds":{"left":0.40555555,"top":0.18333334,"width":0.059722222,"height":0.015555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› pricing","depth":22,"bounds":{"left":0.4652778,"top":0.18333334,"width":0.031944446,"height":0.015555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.50277776,"top":0.17888889,"width":0.019444445,"height":0.022222223},"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"$8.9 / month billed annually.","depth":16,"bounds":{"left":0.37777779,"top":0.24222222,"width":0.12291667,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Learn about AFFiNE AI","depth":17,"bounds":{"left":0.50069445,"top":0.24222222,"width":0.105902776,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". Write with you. Create quality content from sentences to articles on topics you need.","depth":16,"bounds":{"left":0.37777779,"top":0.24222222,"width":0.4173611,"height":0.04222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE is the Next-Gen Knowledge Base to Replace ... Reddit · r/selfhosted 20+ comments · 3 years ago","depth":16,"bounds":{"left":0.37777779,"top":0.33555555,"width":0.3357639,"height":0.048333332},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE is the Next-Gen Knowledge Base to Replace ...","depth":17,"bounds":{"left":0.37777779,"top":0.36333334,"width":0.3357639,"height":0.034444444},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE is the Next-Gen Knowledge Base to Replace ...","depth":18,"bounds":{"left":0.37777779,"top":0.36944443,"width":0.3357639,"height":0.028333334},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Reddit · r/selfhosted","depth":21,"bounds":{"left":0.40555555,"top":0.32333332,"width":0.08715278,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20+ comments · 3 years ago","depth":21,"bounds":{"left":0.40555555,"top":0.34555554,"width":0.105902776,"height":0.015555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.515625,"top":0.34111112,"width":0.019444445,"height":0.022222223},"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":17,"bounds":{"left":0.37777779,"top":0.40444446,"width":0.035069443,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is the Next-Gen Knowledge Base to Replace Notion & Miro. Open-source, privacy-first, and always free. Built with Typescript/React/Rust.","depth":16,"bounds":{"left":0.37777779,"top":0.40444446,"width":0.4298611,"height":0.04222222},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"People also ask","depth":16,"bounds":{"left":0.37777779,"top":0.48333332,"width":0.10451389,"height":0.031111112},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"People also ask","depth":17,"bounds":{"left":0.37777779,"top":0.48333332,"width":0.10451389,"height":0.031111112},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"What is AFFiNE used for?","depth":19,"bounds":{"left":0.37777779,"top":0.5233333,"width":0.45277777,"height":0.057777777},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"What is AFFiNE used for?","depth":22,"bounds":{"left":0.37777779,"top":0.5411111,"width":0.12638889,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Is AFFiNE fully open-source?","depth":19,"bounds":{"left":0.37777779,"top":0.5822222,"width":0.45277777,"height":0.057777777},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Is AFFiNE fully open-source?","depth":22,"bounds":{"left":0.37777779,"top":0.6,"width":0.14479166,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"How to run AFFiNE locally?","depth":19,"bounds":{"left":0.37777779,"top":0.64111114,"width":0.45277777,"height":0.057777777},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"How to run AFFiNE locally?","depth":22,"bounds":{"left":0.37777779,"top":0.6588889,"width":0.134375,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"What is the difference between Docmost and AFFiNE?","depth":19,"bounds":{"left":0.37777779,"top":0.7,"width":0.45277777,"height":0.057777777},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"What is the difference between Docmost and AFFiNE?","depth":22,"bounds":{"left":0.37777779,"top":0.7177778,"width":0.27291667,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"People also search for","depth":14,"bounds":{"left":0.37777779,"top":0.8066667,"width":0.15104167,"height":0.031111112},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"People also search for","depth":15,"bounds":{"left":0.37777779,"top":0.8066667,"width":0.15104167,"height":0.031111112},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Affine mac free download","depth":15,"bounds":{"left":0.37777779,"top":0.84444445,"width":0.22083333,"height":0.06666667},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Affine mac","depth":18,"bounds":{"left":0.3888889,"top":0.8666667,"width":0.056944445,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"free download","depth":18,"bounds":{"left":0.44583333,"top":0.8666667,"width":0.07777778,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE API","depth":15,"bounds":{"left":0.37777779,"top":0.9111111,"width":0.22083333,"height":0.06666667},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"bounds":{"left":0.3888889,"top":0.93333334,"width":0.03923611,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"API","depth":18,"bounds":{"left":0.428125,"top":0.93333334,"width":0.018402778,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE plugins","depth":15,"bounds":{"left":0.37777779,"top":0.9777778,"width":0.22083333,"height":0.02222222},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"bounds":{"left":0.3888889,"top":1.0,"width":0.03923611,"height":0.0},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"plugins","depth":18,"bounds":{"left":0.428125,"top":1.0,"width":0.03923611,"height":0.0},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE iOS","depth":15,"bounds":{"left":0.37777779,"top":1.0,"width":0.22083333,"height":-0.04444444},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"bounds":{"left":0.3888889,"top":1.0,"width":0.03923611,"height":-0.06666672},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"iOS","depth":18,"bounds":{"left":0.428125,"top":1.0,"width":0.019097222,"height":-0.06666672},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE iPad","depth":15,"bounds":{"left":0.6097222,"top":0.84444445,"width":0.22083333,"height":0.06666667},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"bounds":{"left":0.62083334,"top":0.8666667,"width":0.03923611,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"iPad","depth":18,"bounds":{"left":0.66006947,"top":0.8666667,"width":0.023611112,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE download","depth":15,"bounds":{"left":0.6097222,"top":0.9111111,"width":0.22083333,"height":0.06666667},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"bounds":{"left":0.62083334,"top":0.93333334,"width":0.03923611,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"download","depth":18,"bounds":{"left":0.66006947,"top":0.93333334,"width":0.05277778,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE APK","depth":15,"bounds":{"left":0.6097222,"top":0.9777778,"width":0.22083333,"height":0.02222222},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"bounds":{"left":0.62083334,"top":1.0,"width":0.03923611,"height":0.0},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"APK","depth":18,"bounds":{"left":0.66006947,"top":1.0,"width":0.022569444,"height":0.0},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE AI","depth":15,"bounds":{"left":0.6097222,"top":1.0,"width":0.22083333,"height":-0.04444444},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"bounds":{"left":0.62083334,"top":1.0,"width":0.03923611,"height":-0.06666672},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AI","depth":18,"bounds":{"left":0.66006947,"top":1.0,"width":0.011111111,"height":-0.06666672},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Page navigation","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Page navigation","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 2","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 3","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 4","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 5","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 6","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"6","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 7","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 8","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 9","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 10","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Next","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"Next","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Next","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Footer links","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Footer links","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Results are personalised","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Try without personalisation","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Try without personalisation","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bulgaria","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Manastirski Livadi, Sofia - Based on your places (Home)","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Manastirski Livadi, Sofia","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Based on your places (Home)","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Update location","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Help","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Send feedback","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send feedback","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Privacy","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Privacy","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Terms","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Terms","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
1527475732929063830
|
-7551337041370017825
|
click
|
accessibility
|
NULL
|
Ask Google Gemini
Pull requests · screenpipe/scree Ask Google Gemini
Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
affine mac - Google Search
affine mac - Google Search
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to main content
Skip to main content
Accessibility help
Accessibility help
Accessibility feedback
Accessibility feedback
Go to Google Home
affine mac
affine mac
Clear
Search by voice
Search by image
Search
affine api
affine
api
affine plugins
affine
plugins
affine ios
affine
ios
affine ipad
affine
ipad
affine download
affine
download
affine apk
affine
apk
affine ai
affine
ai
affine web
affine
web
Report inappropriate predictions
Report inappropriate predictions
Google apps
Google Account: Lukáš Koválik ([EMAIL])
AI Mode
AI Mode
All
All
Images
Images
Videos
Videos
Forums
Forums
News
News
Short videos
Short videos
More filters
More
Tools
Tools
Search Results
Search Results
Web results
Web results
Download AFFiNE - Offline Notes, Whiteboards, and Local- ... AFFiNE https://affine.pro › download
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
AFFiNE
https://affine.pro
› download
About this result
Download AFFiNE
for offline docs, visual whiteboards, local-first storage, and desktop productivity across macOS, Windows, Linux, iOS, and Android.
AFFiNE - All In One KnowledgeOS AFFiNE https://affine.pro
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
AFFiNE
https://affine.pro
About this result
AFFiNE
is an open-source, privacy-focused workspace that combines docs, whiteboards, and databases. A free Notion & Miro alternative for individuals and ...
Notes,Whiteboard & AI - AFFiNE - App Store - Apple Apple https://apps.apple.com › app › notes-whiteboard-ai-affine
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Apple
https://apps.apple.com
› app › notes-whiteboard-ai-affine
About this result
Think visually, work smarter.
AFFiNE merges an infinite whiteboard with powerful notes, docs, tasks, and AI
. Convert ideas to text instantly and manage ...
toeverything/AFFiNE: There can be more than Notion and ... GitHub https://github.com › toeverything › affine
toeverything/AFFiNE: There can be more than Notion and ...
toeverything/AFFiNE: There can be more than Notion and ...
GitHub
https://github.com
› toeverything › affine
About this result
AFFiNE
is an open-source, all-in-one workspace and an operating system for all the building blocks that assemble your knowledge base and much more -- wiki, ...
AFFiNE for Mac - Download it from Uptodown for free Uptodown https://affine.en.uptodown.com › Mac › Apps › Business
AFFiNE for Mac - Download it from Uptodown for free
AFFiNE for Mac - Download it from Uptodown for free
Uptodown
https://affine.en.uptodown.com
› Mac › Apps › Business
About this result
AFFiNE is a free and open-source app
that lets you create and manage a knowledge base adaptable to almost any purpose. You can use it as a personal journal, ...
Maintaining Peak Mac Performance for Efficient ... AFFiNE https://affine.pro › Blog
Maintaining Peak Mac Performance for Efficient ...
Maintaining Peak Mac Performance for Efficient ...
AFFiNE
https://affine.pro
› Blog
About this result
Dec 26, 2024
—
Affine contains a large library of templates, intuitive canvas and UX design
. It easily integrates with other platforms to boost performance and ...
affine Homebrew Formulae https://formulae.brew.sh › cask › affine
affine
affine
Homebrew Formulae
https://formulae.brew.sh
› cask › affine
About this result
affine
. Install command: brew install --cask affine. Name: AFFiNE ... Requirements: macOS >= 12. Versions: Intel, tahoe, 0.26.3. sequoia, 0.26.3. sonoma ...
AFFiNE for Mac - Download Softonic https://affine.en.softonic.com › Mac › Productivity
AFFiNE for Mac - Download
AFFiNE for Mac - Download
Softonic
https://affine.en.softonic.com
› Mac › Productivity
About this result
Mar 12, 2026
—
AFFiNE is a free software application designed for Mac users
, focusing on enhancing business and productivity workflows. This program provides a ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ... AFFiNE https://affine.pro › pricing
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE
https://affine.pro
› pricing
About this result
$8.9 / month billed annually.
Learn about AFFiNE AI
. Write with you. Create quality content from sentences to articles on topics you need.
AFFiNE is the Next-Gen Knowledge Base to Replace ... Reddit · r/selfhosted 20+ comments · 3 years ago
AFFiNE is the Next-Gen Knowledge Base to Replace ...
AFFiNE is the Next-Gen Knowledge Base to Replace ...
Reddit · r/selfhosted
20+ comments · 3 years ago
About this result
AFFiNE
is the Next-Gen Knowledge Base to Replace Notion & Miro. Open-source, privacy-first, and always free. Built with Typescript/React/Rust.
People also ask
People also ask
What is AFFiNE used for?
What is AFFiNE used for?
Is AFFiNE fully open-source?
Is AFFiNE fully open-source?
How to run AFFiNE locally?
How to run AFFiNE locally?
What is the difference between Docmost and AFFiNE?
What is the difference between Docmost and AFFiNE?
People also search for
People also search for
Affine mac free download
Affine mac
free download
AFFiNE API
AFFiNE
API
AFFiNE plugins
AFFiNE
plugins
AFFiNE iOS
AFFiNE
iOS
AFFiNE iPad
AFFiNE
iPad
AFFiNE download
AFFiNE
download
AFFiNE APK
AFFiNE
APK
AFFiNE AI
AFFiNE
AI
Page navigation
Page navigation
1
Page 2
2
Page 3
3
Page 4
4
Page 5
5
Page 6
6
Page 7
7
Page 8
8
Page 9
9
Page 10
10
Next
Next
Next
Footer links
Footer links
Results are personalised
-
Try without personalisation
Try without personalisation
Bulgaria
Manastirski Livadi, Sofia - Based on your places (Home)
Manastirski Livadi, Sofia
-
Based on your places (Home)
-
Update location
Help
Help
Send feedback
Send feedback
Privacy
Privacy
Terms
Terms...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10197
|
468
|
6
|
2026-05-08T17:11:02.835741+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260262835_m2.jpg...
|
Firefox
|
affine mac - Google Search — Personal
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
affine mac - Google Search
affine mac - Google Search
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to main content
Skip to main content
Accessibility help
Accessibility help
Accessibility feedback
Accessibility feedback
Go to Google Home
affine mac
affine mac
Clear
Search by voice
Search by image
Search
affine api
affine
api
affine plugins
affine
plugins
affine ios
affine
ios
affine ipad
affine
ipad
affine download
affine
download
affine apk
affine
apk
affine ai
affine
ai
affine web
affine
web
Report inappropriate predictions
Report inappropriate predictions
Google apps
Google Account: Lukáš Koválik ([EMAIL])
AI Mode
AI Mode
All
All
Images
Images
Videos
Videos
Forums
Forums
News
News
Short videos
Short videos
More filters
More
Tools
Tools
Search Results
Search Results
Web results
Web results
Download AFFiNE - Offline Notes, Whiteboards, and Local- ... AFFiNE https://affine.pro › download
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
AFFiNE
https://affine.pro
› download
About this result
Download AFFiNE
for offline docs, visual whiteboards, local-first storage, and desktop productivity across macOS, Windows, Linux, iOS, and Android.
AFFiNE - All In One KnowledgeOS AFFiNE https://affine.pro
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
AFFiNE
https://affine.pro
About this result
AFFiNE
is an open-source, privacy-focused workspace that combines docs, whiteboards, and databases. A free Notion & Miro alternative for individuals and ...
Notes,Whiteboard & AI - AFFiNE - App Store - Apple Apple https://apps.apple.com › app › notes-whiteboard-ai-affine
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Apple
https://apps.apple.com
› app › notes-whiteboard-ai-affine
About this result
Think visually, work smarter.
AFFiNE merges an infinite whiteboard with powerful notes, docs, tasks, and AI
. Convert ideas to text instantly and manage ...
toeverything/AFFiNE: There can be more than Notion and ... GitHub https://github.com › toeverything › affine
toeverything/AFFiNE: There can be more than Notion and ...
toeverything/AFFiNE: There can be more than Notion and ...
GitHub
https://github.com
› toeverything › affine
About this result
AFFiNE
is an open-source, all-in-one workspace and an operating system for all the building blocks that assemble your knowledge base and much more -- wiki, ...
AFFiNE for Mac - Download it from Uptodown for free Uptodown https://affine.en.uptodown.com › Mac › Apps › Business
AFFiNE for Mac - Download it from Uptodown for free
AFFiNE for Mac - Download it from Uptodown for free
Uptodown
https://affine.en.uptodown.com
› Mac › Apps › Business
About this result
AFFiNE is a free and open-source app
that lets you create and manage a knowledge base adaptable to almost any purpose. You can use it as a personal journal, ...
Maintaining Peak Mac Performance for Efficient ... AFFiNE https://affine.pro › Blog
Maintaining Peak Mac Performance for Efficient ...
Maintaining Peak Mac Performance for Efficient ...
AFFiNE
https://affine.pro
› Blog
About this result
Dec 26, 2024
—
Affine contains a large library of templates, intuitive canvas and UX design
. It easily integrates with other platforms to boost performance and ...
affine Homebrew Formulae https://formulae.brew.sh › cask › affine
affine
affine
Homebrew Formulae
https://formulae.brew.sh
› cask › affine
About this result
affine
. Install command: brew install --cask affine. Name: AFFiNE ... Requirements: macOS >= 12. Versions: Intel, tahoe, 0.26.3. sequoia, 0.26.3. sonoma ...
AFFiNE for Mac - Download Softonic https://affine.en.softonic.com › Mac › Productivity
AFFiNE for Mac - Download
AFFiNE for Mac - Download
Softonic
https://affine.en.softonic.com
› Mac › Productivity
About this result
Mar 12, 2026
—
AFFiNE is a free software application designed for Mac users
, focusing on enhancing business and productivity workflows. This program provides a ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ... AFFiNE https://affine.pro › pricing
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE
https://affine.pro
› pricing
About this result
$8.9 / month billed annually.
Learn about AFFiNE AI
. Write with you. Create quality content from sentences to articles on topics you need.
AFFiNE is the Next-Gen Knowledge Base to Replace ... Reddit · r/selfhosted 20+ comments · 3 years ago
AFFiNE is the Next-Gen Knowledge Base to Replace ...
AFFiNE is the Next-Gen Knowledge Base to Replace ...
Reddit · r/selfhosted
20+ comments · 3 years ago
About this result
AFFiNE
is the Next-Gen Knowledge Base to Replace Notion & Miro. Open-source, privacy-first, and always free. Built with Typescript/React/Rust.
People also ask
People also ask
What is AFFiNE used for?
What is AFFiNE used for?
Is AFFiNE fully open-source?
Is AFFiNE fully open-source?
How to run AFFiNE locally?
How to run AFFiNE locally?
What is the difference between Docmost and AFFiNE?
What is the difference between Docmost and AFFiNE?
People also search for
People also search for
Affine mac free download
Affine mac
free download
AFFiNE API
AFFiNE
API
AFFiNE plugins
AFFiNE
plugins
AFFiNE iOS
AFFiNE
iOS
AFFiNE iPad
AFFiNE
iPad
AFFiNE download
AFFiNE
download
AFFiNE APK
AFFiNE
APK
AFFiNE AI
AFFiNE
AI
Page navigation
Page navigation
1
Page 2
2
Page 3
3
Page 4
4
Page 5
5
Page 6
6
Page 7
7
Page 8
8
Page 9
9
Page 10
10
Next
Next
Next
Footer links
Footer links
Results are personalised
-
Try without personalisation
Try without personalisation
Bulgaria
Manastirski Livadi, Sofia - Based on your places (Home)
Manastirski Livadi, Sofia
-
Based on your places (Home)
-
Update location
Help
Help
Send feedback
Send feedback
Privacy
Privacy
Terms
Terms...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"bounds":{"left":0.26097074,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"bounds":{"left":0.27426863,"top":0.09577015,"width":0.03025266,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"bounds":{"left":0.26097074,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"bounds":{"left":0.27426863,"top":0.12849163,"width":0.05069814,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.26097074,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.27426863,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.26097074,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.27426863,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.26097074,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.27426863,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.26097074,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.27426863,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"bounds":{"left":0.26097074,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"bounds":{"left":0.27426863,"top":0.32482043,"width":0.105884306,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"affine mac - Google Search","depth":4,"bounds":{"left":0.26097074,"top":0.3463687,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"affine mac - Google Search","depth":5,"bounds":{"left":0.27426863,"top":0.3575419,"width":0.047539894,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.36236703,"top":0.35355148,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.26379654,"top":0.38068634,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.26379654,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.27476728,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.28590426,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.29704124,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.3081782,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to main content","depth":7,"bounds":{"left":0.37832448,"top":0.09497207,"width":0.03656915,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to main content","depth":8,"bounds":{"left":0.38380983,"top":0.0981644,"width":0.025598405,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Accessibility help","depth":7,"bounds":{"left":0.37832448,"top":0.09497207,"width":0.03656915,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Accessibility help","depth":8,"bounds":{"left":0.38397607,"top":0.0981644,"width":0.025265958,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Accessibility feedback","depth":7,"bounds":{"left":0.37832448,"top":0.11731844,"width":0.03656915,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Accessibility feedback","depth":8,"bounds":{"left":0.38397607,"top":0.12051077,"width":0.025265958,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to Google Home","depth":11,"bounds":{"left":0.39926863,"top":0.07741421,"width":0.030585106,"height":0.026735835},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"affine mac","depth":10,"bounds":{"left":0.45146278,"top":0.070231445,"width":0.21875,"height":0.03990423},"on_screen":true,"value":"affine mac","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"affine mac","depth":11,"bounds":{"left":0.45146278,"top":0.0830008,"width":0.025598405,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Clear","depth":10,"bounds":{"left":0.67021275,"top":0.07102953,"width":0.015957447,"height":0.03990423},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search by voice","depth":10,"bounds":{"left":0.6878325,"top":0.08140463,"width":0.013297873,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search by image","depth":10,"bounds":{"left":0.70113033,"top":0.08140463,"width":0.013297873,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search","depth":10,"bounds":{"left":0.71575797,"top":0.07102953,"width":0.01462766,"height":0.03990423},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"affine api","depth":14,"bounds":{"left":0.45146278,"top":0.11971269,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.11971269,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"api","depth":16,"bounds":{"left":0.46542552,"top":0.11971269,"width":0.00930851,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine plugins","depth":14,"bounds":{"left":0.45146278,"top":0.14565043,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.14565043,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"plugins","depth":16,"bounds":{"left":0.46542552,"top":0.14565043,"width":0.020113032,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine ios","depth":14,"bounds":{"left":0.45146278,"top":0.17158818,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.17158818,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ios","depth":16,"bounds":{"left":0.46542552,"top":0.17158818,"width":0.00880984,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine ipad","depth":14,"bounds":{"left":0.45146278,"top":0.19752593,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.19752593,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ipad","depth":16,"bounds":{"left":0.46542552,"top":0.19752593,"width":0.012632979,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine download","depth":14,"bounds":{"left":0.45146278,"top":0.22346368,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.22346368,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"download","depth":16,"bounds":{"left":0.46542552,"top":0.22346368,"width":0.026595745,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine apk","depth":14,"bounds":{"left":0.45146278,"top":0.24940144,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.24940144,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"apk","depth":16,"bounds":{"left":0.46542552,"top":0.24940144,"width":0.010804521,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine ai","depth":14,"bounds":{"left":0.45146278,"top":0.2753392,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.2753392,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ai","depth":16,"bounds":{"left":0.46542552,"top":0.2753392,"width":0.005984043,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine web","depth":14,"bounds":{"left":0.45146278,"top":0.30127692,"width":0.27260637,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":16,"bounds":{"left":0.45146278,"top":0.30127692,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"web","depth":16,"bounds":{"left":0.46542552,"top":0.30127692,"width":0.012134309,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Report inappropriate predictions","depth":11,"bounds":{"left":0.67004657,"top":0.3320032,"width":0.054022606,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Report inappropriate predictions","depth":13,"bounds":{"left":0.67004657,"top":0.3320032,"width":0.054022606,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Google apps","depth":9,"bounds":{"left":0.9640958,"top":0.075019956,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Google Account: Lukáš Koválik (kovaliklukas@gmail.com)","depth":8,"bounds":{"left":0.9800532,"top":0.075019956,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"AI Mode","depth":17,"bounds":{"left":0.44714096,"top":0.11971269,"width":0.025930852,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI Mode","depth":19,"bounds":{"left":0.45113033,"top":0.13407822,"width":0.017952127,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"All","depth":17,"bounds":{"left":0.4730718,"top":0.11971269,"width":0.013464096,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All","depth":20,"bounds":{"left":0.47706118,"top":0.13407822,"width":0.005485372,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Images","depth":17,"bounds":{"left":0.4865359,"top":0.11971269,"width":0.023769947,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Images","depth":19,"bounds":{"left":0.49052528,"top":0.13407822,"width":0.015791224,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Videos","depth":17,"bounds":{"left":0.5103058,"top":0.11971269,"width":0.022772606,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Videos","depth":19,"bounds":{"left":0.5142952,"top":0.13407822,"width":0.014793883,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Forums","depth":17,"bounds":{"left":0.53307843,"top":0.11971269,"width":0.024268618,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Forums","depth":19,"bounds":{"left":0.53706783,"top":0.13407822,"width":0.016289894,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"News","depth":17,"bounds":{"left":0.55734706,"top":0.11971269,"width":0.019780586,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"News","depth":19,"bounds":{"left":0.56133646,"top":0.13407822,"width":0.011801862,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Short videos","depth":17,"bounds":{"left":0.57712764,"top":0.11971269,"width":0.035738032,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Short videos","depth":19,"bounds":{"left":0.58111703,"top":0.13407822,"width":0.027759308,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More filters","depth":17,"bounds":{"left":0.6128657,"top":0.11971269,"width":0.025099734,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":20,"bounds":{"left":0.616855,"top":0.13407822,"width":0.011136968,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Tools","depth":16,"bounds":{"left":0.63796544,"top":0.11971269,"width":0.02543218,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Tools","depth":18,"bounds":{"left":0.6419548,"top":0.13407822,"width":0.011469414,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Search Results","depth":8,"bounds":{"left":0.37466756,"top":0.15802075,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Search Results","depth":9,"bounds":{"left":0.37466756,"top":0.15841979,"width":0.03158245,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Web results","depth":15,"bounds":{"left":0.45113033,"top":0.19592977,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Web results","depth":16,"bounds":{"left":0.45113033,"top":0.19513169,"width":0.03939495,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Download AFFiNE - Offline Notes, Whiteboards, and Local- ... AFFiNE https://affine.pro › download","depth":16,"bounds":{"left":0.45113033,"top":0.18754987,"width":0.1810173,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Download AFFiNE - Offline Notes, Whiteboards, and Local- ...","depth":17,"bounds":{"left":0.45113033,"top":0.2122905,"width":0.1810173,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Download AFFiNE - Offline Notes, Whiteboards, and Local- ...","depth":18,"bounds":{"left":0.45113033,"top":0.21667998,"width":0.1810173,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"bounds":{"left":0.4644282,"top":0.18355946,"width":0.016289894,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"bounds":{"left":0.4644282,"top":0.19952115,"width":0.028590426,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› download","depth":22,"bounds":{"left":0.49301863,"top":0.19952115,"width":0.020611702,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.5162899,"top":0.1963288,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Download AFFiNE","depth":17,"bounds":{"left":0.45113033,"top":0.24181964,"width":0.040392287,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"for offline docs, visual whiteboards, local-first storage, and desktop productivity across macOS, Windows, Linux, iOS, and Android.","depth":16,"bounds":{"left":0.45113033,"top":0.24181964,"width":0.20345744,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE - All In One KnowledgeOS AFFiNE https://affine.pro","depth":16,"bounds":{"left":0.45113033,"top":0.30407023,"width":0.10006649,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE - All In One KnowledgeOS","depth":17,"bounds":{"left":0.45113033,"top":0.32881084,"width":0.10006649,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":18,"bounds":{"left":0.45113033,"top":0.3332003,"width":0.10006649,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"bounds":{"left":0.4644282,"top":0.30007982,"width":0.016289894,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"bounds":{"left":0.4644282,"top":0.3160415,"width":0.028590426,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.4956782,"top":0.31284916,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":17,"bounds":{"left":0.45113033,"top":0.35834,"width":0.016788565,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is an open-source, privacy-focused workspace that combines docs, whiteboards, and databases. A free Notion & Miro alternative for individuals and ...","depth":16,"bounds":{"left":0.45113033,"top":0.35834,"width":0.1931516,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Notes,Whiteboard & AI - AFFiNE - App Store - Apple Apple https://apps.apple.com › app › notes-whiteboard-ai-affine","depth":16,"bounds":{"left":0.45113033,"top":0.4253791,"width":0.1534242,"height":0.03471668},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Notes,Whiteboard & AI - AFFiNE - App Store - Apple","depth":17,"bounds":{"left":0.45113033,"top":0.44533122,"width":0.1534242,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Notes,Whiteboard & AI - AFFiNE - App Store - Apple","depth":18,"bounds":{"left":0.45113033,"top":0.44972068,"width":0.1534242,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Apple","depth":21,"bounds":{"left":0.4644282,"top":0.41660017,"width":0.011968086,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://apps.apple.com","depth":21,"bounds":{"left":0.4644282,"top":0.43256184,"width":0.040059842,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› app › notes-whiteboard-ai-affine","depth":22,"bounds":{"left":0.50448805,"top":0.43256184,"width":0.059840426,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.56632316,"top":0.4293695,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Think visually, work smarter.","depth":16,"bounds":{"left":0.45113033,"top":0.47486034,"width":0.059341755,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE merges an infinite whiteboard with powerful notes, docs, tasks, and AI","depth":17,"bounds":{"left":0.45113033,"top":0.47486034,"width":0.203125,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". Convert ideas to text instantly and manage ...","depth":16,"bounds":{"left":0.47988698,"top":0.4924182,"width":0.09591091,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"toeverything/AFFiNE: There can be more than Notion and ... GitHub https://github.com › toeverything › affine","depth":16,"bounds":{"left":0.45113033,"top":0.5371109,"width":0.17569813,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"toeverything/AFFiNE: There can be more than Notion and ...","depth":17,"bounds":{"left":0.45113033,"top":0.56185156,"width":0.17569813,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"toeverything/AFFiNE: There can be more than Notion and ...","depth":18,"bounds":{"left":0.45113033,"top":0.566241,"width":0.17569813,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"GitHub","depth":21,"bounds":{"left":0.4644282,"top":0.5331205,"width":0.014461436,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://github.com","depth":21,"bounds":{"left":0.4644282,"top":0.5490822,"width":0.031416222,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› toeverything › affine","depth":22,"bounds":{"left":0.49584442,"top":0.5490822,"width":0.03856383,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.53706783,"top":0.54588985,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":17,"bounds":{"left":0.45113033,"top":0.5913807,"width":0.016788565,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is an open-source, all-in-one workspace and an operating system for all the building blocks that assemble your knowledge base and much more -- wiki, ...","depth":16,"bounds":{"left":0.45113033,"top":0.5913807,"width":0.21392952,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE for Mac - Download it from Uptodown for free Uptodown https://affine.en.uptodown.com › Mac › Apps › Business","depth":16,"bounds":{"left":0.45113033,"top":0.65363127,"width":0.15974069,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE for Mac - Download it from Uptodown for free","depth":17,"bounds":{"left":0.45113033,"top":0.6783719,"width":0.15974069,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE for Mac - Download it from Uptodown for free","depth":18,"bounds":{"left":0.45113033,"top":0.6827614,"width":0.15974069,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Uptodown","depth":21,"bounds":{"left":0.4644282,"top":0.64964086,"width":0.020944148,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.en.uptodown.com","depth":21,"bounds":{"left":0.4644282,"top":0.66560256,"width":0.05418883,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› Mac › Apps › Business","depth":22,"bounds":{"left":0.51861703,"top":0.66560256,"width":0.043550532,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.56482714,"top":0.6624102,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE is a free and open-source app","depth":17,"bounds":{"left":0.45113033,"top":0.70790106,"width":0.084109046,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"that lets you create and manage a knowledge base adaptable to almost any purpose. You can use it as a personal journal, ...","depth":16,"bounds":{"left":0.45113033,"top":0.70790106,"width":0.2122673,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Maintaining Peak Mac Performance for Efficient ... AFFiNE https://affine.pro › Blog","depth":16,"bounds":{"left":0.45113033,"top":0.7701516,"width":0.14777261,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Maintaining Peak Mac Performance for Efficient ...","depth":17,"bounds":{"left":0.45113033,"top":0.79489225,"width":0.14777261,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Maintaining Peak Mac Performance for Efficient ...","depth":18,"bounds":{"left":0.45113033,"top":0.7992817,"width":0.14777261,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"bounds":{"left":0.4644282,"top":0.7661612,"width":0.016289894,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"bounds":{"left":0.4644282,"top":0.7821229,"width":0.028590426,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› Blog","depth":22,"bounds":{"left":0.49301863,"top":0.7821229,"width":0.011469414,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.5071476,"top":0.77893054,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dec 26, 2024","depth":16,"bounds":{"left":0.45113033,"top":0.8244214,"width":0.027759308,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":16,"bounds":{"left":0.4788896,"top":0.8244214,"width":0.0071476065,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Affine contains a large library of templates, intuitive canvas and UX design","depth":17,"bounds":{"left":0.48603722,"top":0.8244214,"width":0.16522606,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". It easily integrates with other platforms to boost performance and ...","depth":16,"bounds":{"left":0.45113033,"top":0.8244214,"width":0.2052859,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"affine Homebrew Formulae https://formulae.brew.sh › cask › affine","depth":16,"bounds":{"left":0.45113033,"top":0.8914605,"width":0.08061835,"height":0.03471668},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"affine","depth":17,"bounds":{"left":0.45113033,"top":0.9114126,"width":0.017287234,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":18,"bounds":{"left":0.45113033,"top":0.91580206,"width":0.017287234,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Homebrew Formulae","depth":21,"bounds":{"left":0.4644282,"top":0.88268155,"width":0.04338431,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://formulae.brew.sh","depth":21,"bounds":{"left":0.4644282,"top":0.89864326,"width":0.042386968,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› cask › affine","depth":22,"bounds":{"left":0.50681514,"top":0.89864326,"width":0.024933511,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.5337433,"top":0.8954509,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"affine","depth":17,"bounds":{"left":0.45113033,"top":0.94094175,"width":0.012466756,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". Install command: brew install --cask affine. Name: AFFiNE ... Requirements: macOS >= 12. Versions: Intel, tahoe, 0.26.3. sequoia, 0.26.3. sonoma ...","depth":16,"bounds":{"left":0.45113033,"top":0.94094175,"width":0.203125,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE for Mac - Download Softonic https://affine.en.softonic.com › Mac › Productivity","depth":16,"bounds":{"left":0.45113033,"top":1.0,"width":0.09923537,"height":-0.0031923056},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE for Mac - Download","depth":17,"bounds":{"left":0.45113033,"top":1.0,"width":0.08194814,"height":-0.027933002},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE for Mac - Download","depth":18,"bounds":{"left":0.45113033,"top":1.0,"width":0.08194814,"height":-0.032322407},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Softonic","depth":21,"bounds":{"left":0.4644282,"top":0.9992019,"width":0.016788565,"height":0.0007981062},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.en.softonic.com","depth":21,"bounds":{"left":0.4644282,"top":1.0,"width":0.05069814,"height":-0.01516366},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› Mac › Productivity","depth":22,"bounds":{"left":0.51512635,"top":1.0,"width":0.03523936,"height":-0.01516366},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.55302525,"top":1.0,"width":0.00930851,"height":-0.011971235},"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Mar 12, 2026","depth":16,"bounds":{"left":0.45113033,"top":1.0,"width":0.027426861,"height":-0.057462096},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":16,"bounds":{"left":0.47855717,"top":1.0,"width":0.0071476065,"height":-0.057462096},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE is a free software application designed for Mac users","depth":17,"bounds":{"left":0.48570478,"top":1.0,"width":0.13530585,"height":-0.057462096},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", focusing on enhancing business and productivity workflows. This program provides a ...","depth":16,"bounds":{"left":0.45113033,"top":1.0,"width":0.19630983,"height":-0.057462096},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ... AFFiNE https://affine.pro › pricing","depth":16,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...","depth":17,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› pricing","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"$8.9 / month billed annually.","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Learn about AFFiNE AI","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". Write with you. Create quality content from sentences to articles on topics you need.","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE is the Next-Gen Knowledge Base to Replace ... Reddit · r/selfhosted 20+ comments · 3 years ago","depth":16,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE is the Next-Gen Knowledge Base to Replace ...","depth":17,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE is the Next-Gen Knowledge Base to Replace ...","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Reddit · r/selfhosted","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20+ comments · 3 years ago","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is the Next-Gen Knowledge Base to Replace Notion & Miro. Open-source, privacy-first, and always free. Built with Typescript/React/Rust.","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"People also ask","depth":16,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"People also ask","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"What is AFFiNE used for?","depth":19,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"What is AFFiNE used for?","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Is AFFiNE fully open-source?","depth":19,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Is AFFiNE fully open-source?","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"How to run AFFiNE locally?","depth":19,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"How to run AFFiNE locally?","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"What is the difference between Docmost and AFFiNE?","depth":19,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"What is the difference between Docmost and AFFiNE?","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"People also search for","depth":14,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"People also search for","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Affine mac free download","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Affine mac","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"free download","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE API","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"API","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE plugins","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"plugins","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE iOS","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"iOS","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE iPad","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"iPad","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE download","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"download","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE APK","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"APK","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE AI","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AI","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Page navigation","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Page navigation","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 2","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 3","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 4","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 5","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 6","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"6","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 7","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 8","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 9","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 10","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Next","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"Next","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Next","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Footer links","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Footer links","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Results are personalised","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Try without personalisation","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Try without personalisation","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bulgaria","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Manastirski Livadi, Sofia - Based on your places (Home)","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Manastirski Livadi, Sofia","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Based on your places (Home)","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Update location","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Help","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Send feedback","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send feedback","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Privacy","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Privacy","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Terms","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Terms","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
8638253604304555913
|
-7551337041370017825
|
visual_change
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
affine mac - Google Search
affine mac - Google Search
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to main content
Skip to main content
Accessibility help
Accessibility help
Accessibility feedback
Accessibility feedback
Go to Google Home
affine mac
affine mac
Clear
Search by voice
Search by image
Search
affine api
affine
api
affine plugins
affine
plugins
affine ios
affine
ios
affine ipad
affine
ipad
affine download
affine
download
affine apk
affine
apk
affine ai
affine
ai
affine web
affine
web
Report inappropriate predictions
Report inappropriate predictions
Google apps
Google Account: Lukáš Koválik ([EMAIL])
AI Mode
AI Mode
All
All
Images
Images
Videos
Videos
Forums
Forums
News
News
Short videos
Short videos
More filters
More
Tools
Tools
Search Results
Search Results
Web results
Web results
Download AFFiNE - Offline Notes, Whiteboards, and Local- ... AFFiNE https://affine.pro › download
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
AFFiNE
https://affine.pro
› download
About this result
Download AFFiNE
for offline docs, visual whiteboards, local-first storage, and desktop productivity across macOS, Windows, Linux, iOS, and Android.
AFFiNE - All In One KnowledgeOS AFFiNE https://affine.pro
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
AFFiNE
https://affine.pro
About this result
AFFiNE
is an open-source, privacy-focused workspace that combines docs, whiteboards, and databases. A free Notion & Miro alternative for individuals and ...
Notes,Whiteboard & AI - AFFiNE - App Store - Apple Apple https://apps.apple.com › app › notes-whiteboard-ai-affine
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Apple
https://apps.apple.com
› app › notes-whiteboard-ai-affine
About this result
Think visually, work smarter.
AFFiNE merges an infinite whiteboard with powerful notes, docs, tasks, and AI
. Convert ideas to text instantly and manage ...
toeverything/AFFiNE: There can be more than Notion and ... GitHub https://github.com › toeverything › affine
toeverything/AFFiNE: There can be more than Notion and ...
toeverything/AFFiNE: There can be more than Notion and ...
GitHub
https://github.com
› toeverything › affine
About this result
AFFiNE
is an open-source, all-in-one workspace and an operating system for all the building blocks that assemble your knowledge base and much more -- wiki, ...
AFFiNE for Mac - Download it from Uptodown for free Uptodown https://affine.en.uptodown.com › Mac › Apps › Business
AFFiNE for Mac - Download it from Uptodown for free
AFFiNE for Mac - Download it from Uptodown for free
Uptodown
https://affine.en.uptodown.com
› Mac › Apps › Business
About this result
AFFiNE is a free and open-source app
that lets you create and manage a knowledge base adaptable to almost any purpose. You can use it as a personal journal, ...
Maintaining Peak Mac Performance for Efficient ... AFFiNE https://affine.pro › Blog
Maintaining Peak Mac Performance for Efficient ...
Maintaining Peak Mac Performance for Efficient ...
AFFiNE
https://affine.pro
› Blog
About this result
Dec 26, 2024
—
Affine contains a large library of templates, intuitive canvas and UX design
. It easily integrates with other platforms to boost performance and ...
affine Homebrew Formulae https://formulae.brew.sh › cask › affine
affine
affine
Homebrew Formulae
https://formulae.brew.sh
› cask › affine
About this result
affine
. Install command: brew install --cask affine. Name: AFFiNE ... Requirements: macOS >= 12. Versions: Intel, tahoe, 0.26.3. sequoia, 0.26.3. sonoma ...
AFFiNE for Mac - Download Softonic https://affine.en.softonic.com › Mac › Productivity
AFFiNE for Mac - Download
AFFiNE for Mac - Download
Softonic
https://affine.en.softonic.com
› Mac › Productivity
About this result
Mar 12, 2026
—
AFFiNE is a free software application designed for Mac users
, focusing on enhancing business and productivity workflows. This program provides a ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ... AFFiNE https://affine.pro › pricing
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE
https://affine.pro
› pricing
About this result
$8.9 / month billed annually.
Learn about AFFiNE AI
. Write with you. Create quality content from sentences to articles on topics you need.
AFFiNE is the Next-Gen Knowledge Base to Replace ... Reddit · r/selfhosted 20+ comments · 3 years ago
AFFiNE is the Next-Gen Knowledge Base to Replace ...
AFFiNE is the Next-Gen Knowledge Base to Replace ...
Reddit · r/selfhosted
20+ comments · 3 years ago
About this result
AFFiNE
is the Next-Gen Knowledge Base to Replace Notion & Miro. Open-source, privacy-first, and always free. Built with Typescript/React/Rust.
People also ask
People also ask
What is AFFiNE used for?
What is AFFiNE used for?
Is AFFiNE fully open-source?
Is AFFiNE fully open-source?
How to run AFFiNE locally?
How to run AFFiNE locally?
What is the difference between Docmost and AFFiNE?
What is the difference between Docmost and AFFiNE?
People also search for
People also search for
Affine mac free download
Affine mac
free download
AFFiNE API
AFFiNE
API
AFFiNE plugins
AFFiNE
plugins
AFFiNE iOS
AFFiNE
iOS
AFFiNE iPad
AFFiNE
iPad
AFFiNE download
AFFiNE
download
AFFiNE APK
AFFiNE
APK
AFFiNE AI
AFFiNE
AI
Page navigation
Page navigation
1
Page 2
2
Page 3
3
Page 4
4
Page 5
5
Page 6
6
Page 7
7
Page 8
8
Page 9
9
Page 10
10
Next
Next
Next
Footer links
Footer links
Results are personalised
-
Try without personalisation
Try without personalisation
Bulgaria
Manastirski Livadi, Sofia - Based on your places (Home)
Manastirski Livadi, Sofia
-
Based on your places (Home)
-
Update location
Help
Help
Send feedback
Send feedback
Privacy
Privacy
Terms
Terms...
|
10196
|
NULL
|
NULL
|
NULL
|
|
10196
|
468
|
5
|
2026-05-08T17:10:47.730835+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260247730_m2.jpg...
|
Firefox
|
affine mac - Google Search — Personal
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
affine mac - Google Search
affine mac - Google Search
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to main content
Skip to main content
Accessibility help
Accessibility help
Accessibility feedback
Accessibility feedback
Go to Google Home
affine mac
affine mac
Clear
Search by voice
Search by image
Search
Google apps
Google Account: Lukáš Koválik ([EMAIL])
AI Mode
AI Mode
All
All
Images
Images
Videos
Videos
Forums
Forums
News
News
Short videos
Short videos
More filters
More
Tools
Tools
Search Results
Search Results
Web results
Web results
Download AFFiNE - Offline Notes, Whiteboards, and Local- ... AFFiNE https://affine.pro › download
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
AFFiNE
https://affine.pro
› download
About this result
Download AFFiNE
for offline docs, visual whiteboards, local-first storage, and desktop productivity across macOS, Windows, Linux, iOS, and Android.
AFFiNE - All In One KnowledgeOS AFFiNE https://affine.pro
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
AFFiNE
https://affine.pro
About this result
AFFiNE
is an open-source, privacy-focused workspace that combines docs, whiteboards, and databases. A free Notion & Miro alternative for individuals and ...
Notes,Whiteboard & AI - AFFiNE - App Store - Apple Apple https://apps.apple.com › app › notes-whiteboard-ai-affine
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Apple
https://apps.apple.com
› app › notes-whiteboard-ai-affine
About this result
Think visually, work smarter.
AFFiNE merges an infinite whiteboard with powerful notes, docs, tasks, and AI
. Convert ideas to text instantly and manage ...
toeverything/AFFiNE: There can be more than Notion and ... GitHub https://github.com › toeverything › affine
toeverything/AFFiNE: There can be more than Notion and ...
toeverything/AFFiNE: There can be more than Notion and ...
GitHub
https://github.com
› toeverything › affine
About this result
AFFiNE
is an open-source, all-in-one workspace and an operating system for all the building blocks that assemble your knowledge base and much more -- wiki, ...
AFFiNE for Mac - Download it from Uptodown for free Uptodown https://affine.en.uptodown.com › Mac › Apps › Business
AFFiNE for Mac - Download it from Uptodown for free
AFFiNE for Mac - Download it from Uptodown for free
Uptodown
https://affine.en.uptodown.com
› Mac › Apps › Business
About this result
AFFiNE is a free and open-source app
that lets you create and manage a knowledge base adaptable to almost any purpose. You can use it as a personal journal, ...
Maintaining Peak Mac Performance for Efficient ... AFFiNE https://affine.pro › Blog
Maintaining Peak Mac Performance for Efficient ...
Maintaining Peak Mac Performance for Efficient ...
AFFiNE
https://affine.pro
› Blog
About this result
Dec 26, 2024
—
Affine contains a large library of templates, intuitive canvas and UX design
. It easily integrates with other platforms to boost performance and ...
affine Homebrew Formulae https://formulae.brew.sh › cask › affine
affine
affine
Homebrew Formulae
https://formulae.brew.sh
› cask › affine
About this result
affine
. Install command: brew install --cask affine. Name: AFFiNE ... Requirements: macOS >= 12. Versions: Intel, tahoe, 0.26.3. sequoia, 0.26.3. sonoma ...
AFFiNE for Mac - Download Softonic https://affine.en.softonic.com › Mac › Productivity
AFFiNE for Mac - Download
AFFiNE for Mac - Download
Softonic
https://affine.en.softonic.com
› Mac › Productivity
About this result
Mar 12, 2026
—
AFFiNE is a free software application designed for Mac users
, focusing on enhancing business and productivity workflows. This program provides a ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ... AFFiNE https://affine.pro › pricing
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE
https://affine.pro
› pricing
About this result
$8.9 / month billed annually.
Learn about AFFiNE AI
. Write with you. Create quality content from sentences to articles on topics you need.
AFFiNE is the Next-Gen Knowledge Base to Replace ... Reddit · r/selfhosted 20+ comments · 3 years ago
AFFiNE is the Next-Gen Knowledge Base to Replace ...
AFFiNE is the Next-Gen Knowledge Base to Replace ...
Reddit · r/selfhosted
20+ comments · 3 years ago
About this result
AFFiNE
is the Next-Gen Knowledge Base to Replace Notion & Miro. Open-source, privacy-first, and always free. Built with Typescript/React/Rust.
People also ask
People also ask
What is AFFiNE used for?
What is AFFiNE used for?
Is AFFiNE fully open-source?
Is AFFiNE fully open-source?
How to run AFFiNE locally?
How to run AFFiNE locally?
What is the difference between Docmost and AFFiNE?
What is the difference between Docmost and AFFiNE?
People also search for
People also search for
Affine mac free download
Affine mac
free download
AFFiNE API
AFFiNE
API
AFFiNE plugins
AFFiNE
plugins
AFFiNE iOS
AFFiNE
iOS
AFFiNE iPad
AFFiNE
iPad
AFFiNE download
AFFiNE
download
AFFiNE APK
AFFiNE
APK
AFFiNE AI
AFFiNE
AI
Page navigation
Page navigation
1
Page 2
2
Page 3
3
Page 4
4
Page 5
5
Page 6
6
Page 7
7
Page 8
8
Page 9
9
Page 10
10
Next
Next
Next
Footer links
Footer links
Results are personalised
-
Try without personalisation
Try without personalisation
Bulgaria
Manastirski Livadi, Sofia - Based on your places (Home)
Manastirski Livadi, Sofia
-
Based on your places (Home)
-
Update location
Help
Help
Send feedback
Send feedback
Privacy
Privacy
Terms
Terms...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"bounds":{"left":0.26097074,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"bounds":{"left":0.27426863,"top":0.09577015,"width":0.03025266,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"bounds":{"left":0.26097074,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"bounds":{"left":0.27426863,"top":0.12849163,"width":0.05069814,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.26097074,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.27426863,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.26097074,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.27426863,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.26097074,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.27426863,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.26097074,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.27426863,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"bounds":{"left":0.26097074,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"bounds":{"left":0.27426863,"top":0.32482043,"width":0.105884306,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"affine mac - Google Search","depth":4,"bounds":{"left":0.26097074,"top":0.3463687,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"affine mac - Google Search","depth":5,"bounds":{"left":0.27426863,"top":0.3575419,"width":0.047539894,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.36236703,"top":0.35355148,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.26379654,"top":0.38068634,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.26379654,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.27476728,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.28590426,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.29704124,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.3081782,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to main content","depth":7,"bounds":{"left":0.37832448,"top":0.0981644,"width":0.03656915,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to main content","depth":8,"bounds":{"left":0.38380983,"top":0.101356745,"width":0.025598405,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Accessibility help","depth":7,"bounds":{"left":0.37832448,"top":0.0981644,"width":0.03656915,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Accessibility help","depth":8,"bounds":{"left":0.38397607,"top":0.101356745,"width":0.025265958,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Accessibility feedback","depth":7,"bounds":{"left":0.37832448,"top":0.12051077,"width":0.03656915,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Accessibility feedback","depth":8,"bounds":{"left":0.38397607,"top":0.123703115,"width":0.025265958,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to Google Home","depth":10,"bounds":{"left":0.39926863,"top":0.08060654,"width":0.030585106,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"affine mac","depth":9,"bounds":{"left":0.45146278,"top":0.07342378,"width":0.21875,"height":0.03990423},"on_screen":true,"value":"affine mac","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"affine mac","depth":10,"bounds":{"left":0.45146278,"top":0.08539505,"width":0.025598405,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Clear","depth":9,"bounds":{"left":0.67021275,"top":0.07342378,"width":0.015957447,"height":0.03990423},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search by voice","depth":9,"bounds":{"left":0.6878325,"top":0.083798885,"width":0.013297873,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search by image","depth":9,"bounds":{"left":0.70113033,"top":0.083798885,"width":0.013297873,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search","depth":9,"bounds":{"left":0.71575797,"top":0.07342378,"width":0.01462766,"height":0.03990423},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Google apps","depth":9,"bounds":{"left":0.9640958,"top":0.07741421,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Google Account: Lukáš Koválik (kovaliklukas@gmail.com)","depth":8,"bounds":{"left":0.9800532,"top":0.07741421,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"AI Mode","depth":17,"bounds":{"left":0.44714096,"top":0.12210695,"width":0.025930852,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI Mode","depth":19,"bounds":{"left":0.45113033,"top":0.13647246,"width":0.017952127,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"All","depth":17,"bounds":{"left":0.4730718,"top":0.12210695,"width":0.013464096,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All","depth":20,"bounds":{"left":0.47706118,"top":0.13647246,"width":0.005485372,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Images","depth":17,"bounds":{"left":0.4865359,"top":0.12210695,"width":0.023769947,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Images","depth":19,"bounds":{"left":0.49052528,"top":0.13647246,"width":0.015791224,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Videos","depth":17,"bounds":{"left":0.5103058,"top":0.12210695,"width":0.022772606,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Videos","depth":19,"bounds":{"left":0.5142952,"top":0.13647246,"width":0.014793883,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Forums","depth":17,"bounds":{"left":0.53307843,"top":0.12210695,"width":0.024268618,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Forums","depth":19,"bounds":{"left":0.53706783,"top":0.13647246,"width":0.016289894,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"News","depth":17,"bounds":{"left":0.55734706,"top":0.12210695,"width":0.019780586,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"News","depth":19,"bounds":{"left":0.56133646,"top":0.13647246,"width":0.011801862,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Short videos","depth":17,"bounds":{"left":0.57712764,"top":0.12210695,"width":0.035738032,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Short videos","depth":19,"bounds":{"left":0.58111703,"top":0.13647246,"width":0.027759308,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More filters","depth":17,"bounds":{"left":0.6128657,"top":0.12210695,"width":0.025099734,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":20,"bounds":{"left":0.616855,"top":0.13647246,"width":0.011136968,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Tools","depth":16,"bounds":{"left":0.63796544,"top":0.12210695,"width":0.02543218,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Tools","depth":18,"bounds":{"left":0.6419548,"top":0.13647246,"width":0.011469414,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Search Results","depth":8,"bounds":{"left":0.37466756,"top":0.16041501,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Search Results","depth":9,"bounds":{"left":0.37466756,"top":0.16041501,"width":0.03158245,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Web results","depth":15,"bounds":{"left":0.45113033,"top":0.19832402,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Web results","depth":16,"bounds":{"left":0.45113033,"top":0.19752593,"width":0.03939495,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Download AFFiNE - Offline Notes, Whiteboards, and Local- ... AFFiNE https://affine.pro › download","depth":16,"bounds":{"left":0.45113033,"top":0.18994413,"width":0.1810173,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Download AFFiNE - Offline Notes, Whiteboards, and Local- ...","depth":17,"bounds":{"left":0.45113033,"top":0.21468475,"width":0.1810173,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Download AFFiNE - Offline Notes, Whiteboards, and Local- ...","depth":18,"bounds":{"left":0.45113033,"top":0.21907422,"width":0.1810173,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"bounds":{"left":0.4644282,"top":0.1859537,"width":0.016289894,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"bounds":{"left":0.4644282,"top":0.2019154,"width":0.028590426,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› download","depth":22,"bounds":{"left":0.49301863,"top":0.2019154,"width":0.020611702,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.5162899,"top":0.19872306,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Download AFFiNE","depth":17,"bounds":{"left":0.45113033,"top":0.2442139,"width":0.040392287,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"for offline docs, visual whiteboards, local-first storage, and desktop productivity across macOS, Windows, Linux, iOS, and Android.","depth":16,"bounds":{"left":0.45113033,"top":0.2442139,"width":0.20345744,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE - All In One KnowledgeOS AFFiNE https://affine.pro","depth":16,"bounds":{"left":0.45113033,"top":0.3064645,"width":0.10006649,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE - All In One KnowledgeOS","depth":17,"bounds":{"left":0.45113033,"top":0.3312051,"width":0.10006649,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":18,"bounds":{"left":0.45113033,"top":0.33559456,"width":0.10006649,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"bounds":{"left":0.4644282,"top":0.30247405,"width":0.016289894,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"bounds":{"left":0.4644282,"top":0.31843576,"width":0.028590426,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.4956782,"top":0.31524342,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":17,"bounds":{"left":0.45113033,"top":0.36073422,"width":0.016788565,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is an open-source, privacy-focused workspace that combines docs, whiteboards, and databases. A free Notion & Miro alternative for individuals and ...","depth":16,"bounds":{"left":0.45113033,"top":0.36073422,"width":0.1931516,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Notes,Whiteboard & AI - AFFiNE - App Store - Apple Apple https://apps.apple.com › app › notes-whiteboard-ai-affine","depth":16,"bounds":{"left":0.45113033,"top":0.4273743,"width":0.1534242,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Notes,Whiteboard & AI - AFFiNE - App Store - Apple","depth":17,"bounds":{"left":0.45113033,"top":0.44772545,"width":0.1534242,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Notes,Whiteboard & AI - AFFiNE - App Store - Apple","depth":18,"bounds":{"left":0.45113033,"top":0.4521149,"width":0.1534242,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Apple","depth":21,"bounds":{"left":0.4644282,"top":0.41899443,"width":0.011968086,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://apps.apple.com","depth":21,"bounds":{"left":0.4644282,"top":0.4349561,"width":0.040059842,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› app › notes-whiteboard-ai-affine","depth":22,"bounds":{"left":0.50448805,"top":0.4349561,"width":0.059840426,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.56632316,"top":0.43176377,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Think visually, work smarter.","depth":16,"bounds":{"left":0.45113033,"top":0.4772546,"width":0.059341755,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE merges an infinite whiteboard with powerful notes, docs, tasks, and AI","depth":17,"bounds":{"left":0.45113033,"top":0.4772546,"width":0.203125,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". Convert ideas to text instantly and manage ...","depth":16,"bounds":{"left":0.47988698,"top":0.49481246,"width":0.09591091,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"toeverything/AFFiNE: There can be more than Notion and ... GitHub https://github.com › toeverything › affine","depth":16,"bounds":{"left":0.45113033,"top":0.5395052,"width":0.17569813,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"toeverything/AFFiNE: There can be more than Notion and ...","depth":17,"bounds":{"left":0.45113033,"top":0.5642458,"width":0.17569813,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"toeverything/AFFiNE: There can be more than Notion and ...","depth":18,"bounds":{"left":0.45113033,"top":0.5686353,"width":0.17569813,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"GitHub","depth":21,"bounds":{"left":0.4644282,"top":0.5355148,"width":0.014461436,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://github.com","depth":21,"bounds":{"left":0.4644282,"top":0.5514765,"width":0.031416222,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› toeverything › affine","depth":22,"bounds":{"left":0.49584442,"top":0.5514765,"width":0.03856383,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.53706783,"top":0.5482841,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":17,"bounds":{"left":0.45113033,"top":0.5937749,"width":0.016788565,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is an open-source, all-in-one workspace and an operating system for all the building blocks that assemble your knowledge base and much more -- wiki, ...","depth":16,"bounds":{"left":0.45113033,"top":0.5937749,"width":0.21392952,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE for Mac - Download it from Uptodown for free Uptodown https://affine.en.uptodown.com › Mac › Apps › Business","depth":16,"bounds":{"left":0.45113033,"top":0.6560255,"width":0.15974069,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE for Mac - Download it from Uptodown for free","depth":17,"bounds":{"left":0.45113033,"top":0.68076617,"width":0.15974069,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE for Mac - Download it from Uptodown for free","depth":18,"bounds":{"left":0.45113033,"top":0.68515563,"width":0.15974069,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Uptodown","depth":21,"bounds":{"left":0.4644282,"top":0.6520351,"width":0.020944148,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.en.uptodown.com","depth":21,"bounds":{"left":0.4644282,"top":0.6679968,"width":0.05418883,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› Mac › Apps › Business","depth":22,"bounds":{"left":0.51861703,"top":0.6679968,"width":0.043550532,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.56482714,"top":0.66480446,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE is a free and open-source app","depth":17,"bounds":{"left":0.45113033,"top":0.7102953,"width":0.084109046,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"that lets you create and manage a knowledge base adaptable to almost any purpose. You can use it as a personal journal, ...","depth":16,"bounds":{"left":0.45113033,"top":0.7102953,"width":0.2122673,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Maintaining Peak Mac Performance for Efficient ... AFFiNE https://affine.pro › Blog","depth":16,"bounds":{"left":0.45113033,"top":0.7725459,"width":0.14777261,"height":0.039505187},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Maintaining Peak Mac Performance for Efficient ...","depth":17,"bounds":{"left":0.45113033,"top":0.7972865,"width":0.14777261,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Maintaining Peak Mac Performance for Efficient ...","depth":18,"bounds":{"left":0.45113033,"top":0.801676,"width":0.14777261,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"bounds":{"left":0.4644282,"top":0.76855546,"width":0.016289894,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"bounds":{"left":0.4644282,"top":0.78451717,"width":0.028590426,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› Blog","depth":22,"bounds":{"left":0.49301863,"top":0.78451717,"width":0.011469414,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.5071476,"top":0.7813248,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dec 26, 2024","depth":16,"bounds":{"left":0.45113033,"top":0.82681566,"width":0.027759308,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":16,"bounds":{"left":0.4788896,"top":0.82681566,"width":0.0071476065,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Affine contains a large library of templates, intuitive canvas and UX design","depth":17,"bounds":{"left":0.48603722,"top":0.82681566,"width":0.16522606,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". It easily integrates with other platforms to boost performance and ...","depth":16,"bounds":{"left":0.45113033,"top":0.82681566,"width":0.2052859,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"affine Homebrew Formulae https://formulae.brew.sh › cask › affine","depth":16,"bounds":{"left":0.45113033,"top":0.8934557,"width":0.08061835,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"affine","depth":17,"bounds":{"left":0.45113033,"top":0.91380686,"width":0.017287234,"height":0.024740623},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"affine","depth":18,"bounds":{"left":0.45113033,"top":0.9181963,"width":0.017287234,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Homebrew Formulae","depth":21,"bounds":{"left":0.4644282,"top":0.8850758,"width":0.04338431,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://formulae.brew.sh","depth":21,"bounds":{"left":0.4644282,"top":0.9010375,"width":0.042386968,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› cask › affine","depth":22,"bounds":{"left":0.50681514,"top":0.9010375,"width":0.024933511,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.5337433,"top":0.89784515,"width":0.00930851,"height":0.015961692},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"affine","depth":17,"bounds":{"left":0.45113033,"top":0.943336,"width":0.012466756,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". Install command: brew install --cask affine. Name: AFFiNE ... Requirements: macOS >= 12. Versions: Intel, tahoe, 0.26.3. sequoia, 0.26.3. sonoma ...","depth":16,"bounds":{"left":0.45113033,"top":0.943336,"width":0.203125,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE for Mac - Download Softonic https://affine.en.softonic.com › Mac › Productivity","depth":16,"bounds":{"left":0.45113033,"top":1.0,"width":0.09923537,"height":-0.005586624},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE for Mac - Download","depth":17,"bounds":{"left":0.45113033,"top":1.0,"width":0.08194814,"height":-0.0303272},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE for Mac - Download","depth":18,"bounds":{"left":0.45113033,"top":1.0,"width":0.08194814,"height":-0.034716725},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Softonic","depth":21,"bounds":{"left":0.4644282,"top":1.0,"width":0.016788565,"height":-0.0015962124},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.en.softonic.com","depth":21,"bounds":{"left":0.4644282,"top":1.0,"width":0.05069814,"height":-0.01755786},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› Mac › Productivity","depth":22,"bounds":{"left":0.51512635,"top":1.0,"width":0.03523936,"height":-0.01755786},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"bounds":{"left":0.55302525,"top":1.0,"width":0.00930851,"height":-0.014365554},"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Mar 12, 2026","depth":16,"bounds":{"left":0.45113033,"top":1.0,"width":0.027426861,"height":-0.059856296},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":16,"bounds":{"left":0.47855717,"top":1.0,"width":0.0071476065,"height":-0.059856296},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE is a free software application designed for Mac users","depth":17,"bounds":{"left":0.48570478,"top":1.0,"width":0.13530585,"height":-0.059856296},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", focusing on enhancing business and productivity workflows. This program provides a ...","depth":16,"bounds":{"left":0.45113033,"top":1.0,"width":0.19630983,"height":-0.059856296},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ... AFFiNE https://affine.pro › pricing","depth":16,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...","depth":17,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"https://affine.pro","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"› pricing","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"$8.9 / month billed annually.","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Learn about AFFiNE AI","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". Write with you. Create quality content from sentences to articles on topics you need.","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE is the Next-Gen Knowledge Base to Replace ... Reddit · r/selfhosted 20+ comments · 3 years ago","depth":16,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AFFiNE is the Next-Gen Knowledge Base to Replace ...","depth":17,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AFFiNE is the Next-Gen Knowledge Base to Replace ...","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Reddit · r/selfhosted","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20+ comments · 3 years ago","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"About this result","depth":16,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is the Next-Gen Knowledge Base to Replace Notion & Miro. Open-source, privacy-first, and always free. Built with Typescript/React/Rust.","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"People also ask","depth":16,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"People also ask","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"What is AFFiNE used for?","depth":19,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"What is AFFiNE used for?","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Is AFFiNE fully open-source?","depth":19,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Is AFFiNE fully open-source?","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"How to run AFFiNE locally?","depth":19,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"How to run AFFiNE locally?","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"What is the difference between Docmost and AFFiNE?","depth":19,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"What is the difference between Docmost and AFFiNE?","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"People also search for","depth":14,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"People also search for","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Affine mac free download","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Affine mac","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"free download","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE API","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"API","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE plugins","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"plugins","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE iOS","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"iOS","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE iPad","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"iPad","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE download","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"download","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE APK","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"APK","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AFFiNE AI","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AI","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Page navigation","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Page navigation","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 2","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 3","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 4","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 5","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 6","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"6","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 7","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 8","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 9","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 10","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Next","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"Next","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Next","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Footer links","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Footer links","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Results are personalised","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Try without personalisation","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Try without personalisation","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bulgaria","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Manastirski Livadi, Sofia - Based on your places (Home)","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Manastirski Livadi, Sofia","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Based on your places (Home)","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Update location","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Help","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Send feedback","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send feedback","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Privacy","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Privacy","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Terms","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Terms","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
4503231233412255147
|
-7551339309112750113
|
visual_change
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
affine mac - Google Search
affine mac - Google Search
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to main content
Skip to main content
Accessibility help
Accessibility help
Accessibility feedback
Accessibility feedback
Go to Google Home
affine mac
affine mac
Clear
Search by voice
Search by image
Search
Google apps
Google Account: Lukáš Koválik ([EMAIL])
AI Mode
AI Mode
All
All
Images
Images
Videos
Videos
Forums
Forums
News
News
Short videos
Short videos
More filters
More
Tools
Tools
Search Results
Search Results
Web results
Web results
Download AFFiNE - Offline Notes, Whiteboards, and Local- ... AFFiNE https://affine.pro › download
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
Download AFFiNE - Offline Notes, Whiteboards, and Local- ...
AFFiNE
https://affine.pro
› download
About this result
Download AFFiNE
for offline docs, visual whiteboards, local-first storage, and desktop productivity across macOS, Windows, Linux, iOS, and Android.
AFFiNE - All In One KnowledgeOS AFFiNE https://affine.pro
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
AFFiNE
https://affine.pro
About this result
AFFiNE
is an open-source, privacy-focused workspace that combines docs, whiteboards, and databases. A free Notion & Miro alternative for individuals and ...
Notes,Whiteboard & AI - AFFiNE - App Store - Apple Apple https://apps.apple.com › app › notes-whiteboard-ai-affine
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Notes,Whiteboard & AI - AFFiNE - App Store - Apple
Apple
https://apps.apple.com
› app › notes-whiteboard-ai-affine
About this result
Think visually, work smarter.
AFFiNE merges an infinite whiteboard with powerful notes, docs, tasks, and AI
. Convert ideas to text instantly and manage ...
toeverything/AFFiNE: There can be more than Notion and ... GitHub https://github.com › toeverything › affine
toeverything/AFFiNE: There can be more than Notion and ...
toeverything/AFFiNE: There can be more than Notion and ...
GitHub
https://github.com
› toeverything › affine
About this result
AFFiNE
is an open-source, all-in-one workspace and an operating system for all the building blocks that assemble your knowledge base and much more -- wiki, ...
AFFiNE for Mac - Download it from Uptodown for free Uptodown https://affine.en.uptodown.com › Mac › Apps › Business
AFFiNE for Mac - Download it from Uptodown for free
AFFiNE for Mac - Download it from Uptodown for free
Uptodown
https://affine.en.uptodown.com
› Mac › Apps › Business
About this result
AFFiNE is a free and open-source app
that lets you create and manage a knowledge base adaptable to almost any purpose. You can use it as a personal journal, ...
Maintaining Peak Mac Performance for Efficient ... AFFiNE https://affine.pro › Blog
Maintaining Peak Mac Performance for Efficient ...
Maintaining Peak Mac Performance for Efficient ...
AFFiNE
https://affine.pro
› Blog
About this result
Dec 26, 2024
—
Affine contains a large library of templates, intuitive canvas and UX design
. It easily integrates with other platforms to boost performance and ...
affine Homebrew Formulae https://formulae.brew.sh › cask › affine
affine
affine
Homebrew Formulae
https://formulae.brew.sh
› cask › affine
About this result
affine
. Install command: brew install --cask affine. Name: AFFiNE ... Requirements: macOS >= 12. Versions: Intel, tahoe, 0.26.3. sequoia, 0.26.3. sonoma ...
AFFiNE for Mac - Download Softonic https://affine.en.softonic.com › Mac › Productivity
AFFiNE for Mac - Download
AFFiNE for Mac - Download
Softonic
https://affine.en.softonic.com
› Mac › Productivity
About this result
Mar 12, 2026
—
AFFiNE is a free software application designed for Mac users
, focusing on enhancing business and productivity workflows. This program provides a ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ... AFFiNE https://affine.pro › pricing
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE Pricing - Plans for Notes, Whiteboards, AI, and ...
AFFiNE
https://affine.pro
› pricing
About this result
$8.9 / month billed annually.
Learn about AFFiNE AI
. Write with you. Create quality content from sentences to articles on topics you need.
AFFiNE is the Next-Gen Knowledge Base to Replace ... Reddit · r/selfhosted 20+ comments · 3 years ago
AFFiNE is the Next-Gen Knowledge Base to Replace ...
AFFiNE is the Next-Gen Knowledge Base to Replace ...
Reddit · r/selfhosted
20+ comments · 3 years ago
About this result
AFFiNE
is the Next-Gen Knowledge Base to Replace Notion & Miro. Open-source, privacy-first, and always free. Built with Typescript/React/Rust.
People also ask
People also ask
What is AFFiNE used for?
What is AFFiNE used for?
Is AFFiNE fully open-source?
Is AFFiNE fully open-source?
How to run AFFiNE locally?
How to run AFFiNE locally?
What is the difference between Docmost and AFFiNE?
What is the difference between Docmost and AFFiNE?
People also search for
People also search for
Affine mac free download
Affine mac
free download
AFFiNE API
AFFiNE
API
AFFiNE plugins
AFFiNE
plugins
AFFiNE iOS
AFFiNE
iOS
AFFiNE iPad
AFFiNE
iPad
AFFiNE download
AFFiNE
download
AFFiNE APK
AFFiNE
APK
AFFiNE AI
AFFiNE
AI
Page navigation
Page navigation
1
Page 2
2
Page 3
3
Page 4
4
Page 5
5
Page 6
6
Page 7
7
Page 8
8
Page 9
9
Page 10
10
Next
Next
Next
Footer links
Footer links
Results are personalised
-
Try without personalisation
Try without personalisation
Bulgaria
Manastirski Livadi, Sofia - Based on your places (Home)
Manastirski Livadi, Sofia
-
Based on your places (Home)
-
Update location
Help
Help
Send feedback
Send feedback
Privacy
Privacy
Terms
Terms...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10195
|
468
|
4
|
2026-05-08T17:10:43.091191+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260243091_m2.jpg...
|
Firefox
|
Personal — Mozilla Firefox
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Close tab
New Tab
New Tab
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
22°
C
New York City
Open menu
Mozilla Firefox
Search with Google or enter address
Search with Google or enter address
Inbox (11) - [EMAIL] - Gmail
Inbox (11) - [EMAIL] - Gmail
Open context menu for Inbox (11) - [EMAIL] - Gmail
(137) YouTube
(137) YouTube
Open context menu for (137) YouTube
Screenpipe — Archive
Screenpipe — Archive
Open context menu for Screenpipe — Archive
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
Open context menu for screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
Screenpipe — Archive
Screenpipe — Archive
Open context menu for Screenpipe — Archive
Denník N - Nezávislý denník
Denník N - Nezávislý denník
Open context menu for Denník N - Nezávislý denník
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Open context menu for DXP4800PLUS-B5F8
(58) Inbox | [EMAIL] | Proton Mail
(58) Inbox | [EMAIL] | Proton Mail
Open context menu for (58) Inbox | [EMAIL] | Proton Mail
Customize
Customize...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.074221864,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.08539505,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"bounds":{"left":0.26097074,"top":0.10694334,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"bounds":{"left":0.27426863,"top":0.11811652,"width":0.03025266,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"bounds":{"left":0.26097074,"top":0.1396648,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"bounds":{"left":0.27426863,"top":0.15083799,"width":0.05069814,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.26097074,"top":0.17238627,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.27426863,"top":0.18355946,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.26097074,"top":0.20510775,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.27426863,"top":0.21628092,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.26097074,"top":0.23782921,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.27426863,"top":0.2490024,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.27055067,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.28172386,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.26097074,"top":0.30327216,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.27426863,"top":0.31444532,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"bounds":{"left":0.26097074,"top":0.33599362,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"bounds":{"left":0.27426863,"top":0.3471668,"width":0.105884306,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.36236703,"top":0.34317636,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.26097074,"top":0.36871508,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.27426863,"top":0.37988827,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.36236703,"top":0.37589785,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.26379654,"top":0.40303272,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.26379654,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.27476728,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.28590426,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.29704124,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.3081782,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"22°","depth":8,"bounds":{"left":0.94148934,"top":0.10415004,"width":0.00930851,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"C","depth":8,"bounds":{"left":0.95079786,"top":0.10415004,"width":0.0039893617,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"New York City","depth":8,"bounds":{"left":0.94148934,"top":0.12051077,"width":0.02825798,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Open menu","depth":7,"bounds":{"left":0.9734042,"top":0.0981644,"width":0.01662234,"height":0.043894652},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Mozilla Firefox","depth":9,"bounds":{"left":0.4694149,"top":0.40782124,"width":0.43583778,"height":0.051077414},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Search with Google or enter address","depth":9,"bounds":{"left":0.56765294,"top":0.4828412,"width":0.2393617,"height":0.0415004},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search with Google or enter address","depth":11,"bounds":{"left":0.58427525,"top":0.4960096,"width":0.08344415,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Inbox (11) - kovaliklukas@gmail.com - Gmail","depth":12,"bounds":{"left":0.5277593,"top":0.5482841,"width":0.039893616,"height":0.09736632},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (11) - kovaliklukas@gmail.com - Gmail","depth":14,"bounds":{"left":0.53241354,"top":0.61731845,"width":0.030585106,"height":0.051077414},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for Inbox (11) - kovaliklukas@gmail.com - Gmail","depth":12,"bounds":{"left":0.5596742,"top":0.55706304,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"(137) YouTube","depth":12,"bounds":{"left":0.56765294,"top":0.5482841,"width":0.039893616,"height":0.09736632},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(137) YouTube","depth":14,"bounds":{"left":0.57330453,"top":0.61731845,"width":0.028590426,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for (137) YouTube","depth":12,"bounds":{"left":0.59956783,"top":0.55706304,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Screenpipe — Archive","depth":12,"bounds":{"left":0.60754657,"top":0.5482841,"width":0.039893616,"height":0.09736632},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":14,"bounds":{"left":0.6136968,"top":0.61731845,"width":0.027593086,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for Screenpipe — Archive","depth":12,"bounds":{"left":0.63946146,"top":0.55706304,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":12,"bounds":{"left":0.64744014,"top":0.5482841,"width":0.039893616,"height":0.09736632},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":14,"bounds":{"left":0.65226066,"top":0.61731845,"width":0.03025266,"height":0.07661612},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":12,"bounds":{"left":0.679355,"top":0.55706304,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Screenpipe — Archive","depth":12,"bounds":{"left":0.68733376,"top":0.5482841,"width":0.039893616,"height":0.09736632},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":14,"bounds":{"left":0.69348407,"top":0.61731845,"width":0.027593086,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for Screenpipe — Archive","depth":12,"bounds":{"left":0.71924865,"top":0.55706304,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Denník N - Nezávislý denník","depth":12,"bounds":{"left":0.7272274,"top":0.5482841,"width":0.039893616,"height":0.09736632},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Denník N - Nezávislý denník","depth":14,"bounds":{"left":0.73636967,"top":0.61731845,"width":0.021609042,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for Denník N - Nezávislý denník","depth":12,"bounds":{"left":0.7591423,"top":0.55706304,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"DXP4800PLUS-B5F8","depth":12,"bounds":{"left":0.767121,"top":0.5482841,"width":0.039893616,"height":0.09736632},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":14,"bounds":{"left":0.7719415,"top":0.61731845,"width":0.03025266,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for DXP4800PLUS-B5F8","depth":12,"bounds":{"left":0.7990359,"top":0.55706304,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"(58) Inbox | kovaliklukas@proton.me | Proton Mail","depth":12,"bounds":{"left":0.80701464,"top":0.5482841,"width":0.039893616,"height":0.09736632},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(58) Inbox | kovaliklukas@proton.me | Proton Mail","depth":14,"bounds":{"left":0.8116689,"top":0.61731845,"width":0.030585106,"height":0.051077414},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for (58) Inbox | kovaliklukas@proton.me | Proton Mail","depth":12,"bounds":{"left":0.83892953,"top":0.55706304,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Customize","depth":8,"bounds":{"left":0.97955453,"top":0.9509178,"width":0.012965426,"height":0.0311253},"on_screen":true,"help_text":"Customize this page","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Customize","depth":10,"bounds":{"left":0.98271275,"top":0.95929766,"width":0.017287254,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
4711515230144858250
|
-687782836418882046
|
click
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Close tab
New Tab
New Tab
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
22°
C
New York City
Open menu
Mozilla Firefox
Search with Google or enter address
Search with Google or enter address
Inbox (11) - [EMAIL] - Gmail
Inbox (11) - [EMAIL] - Gmail
Open context menu for Inbox (11) - [EMAIL] - Gmail
(137) YouTube
(137) YouTube
Open context menu for (137) YouTube
Screenpipe — Archive
Screenpipe — Archive
Open context menu for Screenpipe — Archive
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
Open context menu for screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
Screenpipe — Archive
Screenpipe — Archive
Open context menu for Screenpipe — Archive
Denník N - Nezávislý denník
Denník N - Nezávislý denník
Open context menu for Denník N - Nezávislý denník
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Open context menu for DXP4800PLUS-B5F8
(58) Inbox | [EMAIL] | Proton Mail
(58) Inbox | [EMAIL] | Proton Mail
Open context menu for (58) Inbox | [EMAIL] | Proton Mail
Customize
Customize...
|
10191
|
NULL
|
NULL
|
NULL
|
|
10194
|
467
|
6
|
2026-05-08T17:10:43.091190+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260243091_m1.jpg...
|
Firefox
|
Personal — Mozilla Firefox
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Close tab
New Tab
New Tab
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
22°
C
New York City
Open menu
Mozilla Firefox
Search with Google or enter address
Search with Google or enter address
Inbox (11) - [EMAIL] - Gmail
Inbox (11) - [EMAIL] - Gmail
Open context menu for Inbox (11) - [EMAIL] - Gmail
(137) YouTube
(137) YouTube
Open context menu for (137) YouTube
Screenpipe — Archive
Screenpipe — Archive
Open context menu for Screenpipe — Archive
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
Open context menu for screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
Screenpipe — Archive
Screenpipe — Archive
Open context menu for Screenpipe — Archive
Denník N - Nezávislý denník
Denník N - Nezávislý denník
Open context menu for Denník N - Nezávislý denník
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Open context menu for DXP4800PLUS-B5F8
(58) Inbox | [EMAIL] | Proton Mail
(58) Inbox | [EMAIL] | Proton Mail
Open context menu for (58) Inbox | [EMAIL] | Proton Mail
Customize
Customize...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.009375,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.03263889,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.05590278,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.079166666,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"22°","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"C","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"New York City","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Open menu","depth":7,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Mozilla Firefox","depth":9,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Search with Google or enter address","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search with Google or enter address","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Inbox (11) - kovaliklukas@gmail.com - Gmail","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (11) - kovaliklukas@gmail.com - Gmail","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for Inbox (11) - kovaliklukas@gmail.com - Gmail","depth":12,"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"(137) YouTube","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(137) YouTube","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for (137) YouTube","depth":12,"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Screenpipe — Archive","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for Screenpipe — Archive","depth":12,"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":12,"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Screenpipe — Archive","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for Screenpipe — Archive","depth":12,"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Denník N - Nezávislý denník","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Denník N - Nezávislý denník","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for Denník N - Nezávislý denník","depth":12,"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"DXP4800PLUS-B5F8","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for DXP4800PLUS-B5F8","depth":12,"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"(58) Inbox | kovaliklukas@proton.me | Proton Mail","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(58) Inbox | kovaliklukas@proton.me | Proton Mail","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open context menu for (58) Inbox | kovaliklukas@proton.me | Proton Mail","depth":12,"on_screen":true,"help_text":"Open menu","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Customize","depth":8,"on_screen":true,"help_text":"Customize this page","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Customize","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
4711515230144858250
|
-687782836418882046
|
click
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Close tab
New Tab
New Tab
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
22°
C
New York City
Open menu
Mozilla Firefox
Search with Google or enter address
Search with Google or enter address
Inbox (11) - [EMAIL] - Gmail
Inbox (11) - [EMAIL] - Gmail
Open context menu for Inbox (11) - [EMAIL] - Gmail
(137) YouTube
(137) YouTube
Open context menu for (137) YouTube
Screenpipe — Archive
Screenpipe — Archive
Open context menu for Screenpipe — Archive
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
Open context menu for screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
Screenpipe — Archive
Screenpipe — Archive
Open context menu for Screenpipe — Archive
Denník N - Nezávislý denník
Denník N - Nezávislý denník
Open context menu for Denník N - Nezávislý denník
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Open context menu for DXP4800PLUS-B5F8
(58) Inbox | [EMAIL] | Proton Mail
(58) Inbox | [EMAIL] | Proton Mail
Open context menu for (58) Inbox | [EMAIL] | Proton Mail
Customize
Customize...
|
10193
|
NULL
|
NULL
|
NULL
|
|
10193
|
467
|
5
|
2026-05-08T17:10:36.000723+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260236000_m1.jpg...
|
Firefox
|
Pull requests · screenpipe/screenpipe · GitHub — P Pull requests · screenpipe/screenpipe · GitHub — Personal...
|
1
|
github.com/screenpipe/screenpipe/pulls?page=2& github.com/screenpipe/screenpipe/pulls?page=2&q=is%3Apr+is%3Aclosed...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Close tab
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to content
Skip to content
Navigation Menu
Navigation Menu
Homepage
Platform
Solutions
Resources
Open Source
Enterprise
Pricing
Pricing
Search or jump to…
Search or jump to...
Sign in
Sign in
Sign up
Sign up
Appearance settings
screenpipe
screenpipe
/
screenpipe
screenpipe
Public
You must be signed in to change notification settings
Notifications
Fork 1.7k
Fork
1.7k
You must be signed in to star a repository
Star
18.6k
Code
Code
Issues 16
Issues
16
Pull requests 17
Pull requests
17
Discussions
Discussions
Actions
Actions
Projects
Projects
Security and quality
Security and quality
Insights
Insights
Pull requests: screenpipe/screenpipe
Pull requests: screenpipe/screenpipe
is:pr is:closed
Labels 43
Labels
43
Milestones 0
Milestones
0
New pull request
New pull request
Clear current search query, filters, and sorts
Clear current search query, filters, and sorts
17 Open
17 Open
1,593 Closed
1,593 Closed
Author
Author
Label
Label
Projects
Projects
Milestones
Milestones
Reviews
Reviews
Assignee
Assignee
Sort
Sort
Pull requests list
Pull requests list
docs(testing): add 3 recent regression test entries
docs(testing): add 3 recent regression test entries
#3224 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
testing: update spec from recent changes (2026-05-04)
testing: update spec from recent changes (2026-05-04)
#3223 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add circuit breaker for corrupted segmentation model
fix: add circuit breaker for corrupted segmentation model
#3222 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add a11y multi-line bbox regression entry
docs(testing): add a11y multi-line bbox regression entry
#3221 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add diagnostic logging for audio device configuration selection
fix: add diagnostic logging for audio device configuration selection
#3220 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs: improve SEO titles across generic pages
docs: improve SEO titles across generic pages
#3219 by
mintlify
mintlify
Bot
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3218 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add multi-line text bbox capture regression test
docs(testing): add multi-line text bbox capture regression test
#3217 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Windows GetWindowRect bounds regression test
docs(testing): add Windows GetWindowRect bounds regression test
#3216 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
Fix devcontainer cargo path
Fix devcontainer cargo path
#3214 by
julpel8
julpel8
Contributor
was merged
4 days ago
•
Review required before merging
Review required
fix(settings): api key regenerate cancel, apply button, manual edit
fix(settings): api key regenerate cancel, apply button, manual edit
#3212 by
Anshgrover23
Anshgrover23
Contributor
was merged
5 days ago
•
Review required before merging
Review required
docs(testing): add VACUUM INTO snapshot regression entry
docs(testing): add VACUUM INTO snapshot regression entry
#3211 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix(chat): allow input chip to be removed
fix(chat): allow input chip to be removed
#3210 by
thisisharsh7
thisisharsh7
Contributor
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
fix: graceful fallback when segmentation model cache is invalidated
fix: graceful fallback when segmentation model cache is invalidated
#3209 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
testing: update spec from recent changes (2026-05-03)
testing: update spec from recent changes (2026-05-03)
#3208 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add empty-state navigation button regression test
docs(testing): add empty-state navigation button regression test
#3207 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: audio dedup-skip metric — prevent false health check stalls
fix: audio dedup-skip metric — prevent false health check stalls
#3206 by
louis030195
louis030195
Collaborator
was closed
2 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3204 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add per-line search highlight regression test
docs(testing): add per-line search highlight regression test
#3203 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Apple Vision per-word OCR fast path regression test
docs(testing): add Apple Vision per-word OCR fast path regression test
#3202 by
louis030195
louis030195
Collaborator
was merged
last week
•
Review required before merging
Review required
docs(testing): add Windows AVX2 CPU support regression entry
docs(testing): add Windows AVX2 CPU support regression entry
#3201 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
docs(testing): add timeline Escape key regression test for Windows
docs(testing): add timeline Escape key regression test for Windows
#3200 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
fix: preserve original db error in write queue instead of masking with PoolTimedOut
fix: preserve original db error in write queue instead of masking with PoolTimedOut
#3199 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
testing: update spec from recent changes (2026-05-02)
testing: update spec from recent changes (2026-05-02)
#3198 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
docs(testing): add Bluetooth audio device hijack recovery regression test
docs(testing): add Bluetooth audio device hijack recovery regression test
#3197 by
louis030195
louis030195
Collaborator
was merged
last week
•
Review required before merging
Review required
Previous page
Previous
Page 1
1
2
Page 3
3
Page 4
4
Page 5
5
…
Page 63
63
Page 64
64
Next page
Next
ProTip!
Adding
no:label
no:label
will show everything without a label.
Footer
Footer
GitHub Homepage
© 2026 GitHub, Inc.
Footer navigation
Footer navigation
Terms
Terms
Privacy
Privacy
Security
Security
Status
Status
Community
Community
Docs
Docs
Contact
Contact
Manage cookies
Do not share my personal information...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.009375,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.03263889,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.05590278,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.079166666,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to content","depth":6,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Navigation Menu","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Navigation Menu","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Homepage","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Platform","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Solutions","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Resources","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Source","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Enterprise","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Pricing","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pricing","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search or jump to...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sign in","depth":8,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sign in","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sign up","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sign up","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Appearance settings","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"screenpipe","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"screenpipe","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"You must be signed in to change notification settings","depth":11,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fork 1.7k","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fork","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1.7k","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"You must be signed in to star a repository","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Star","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18.6k","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Issues 16","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests 17","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Discussions","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Discussions","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Projects","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Projects","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull requests: screenpipe/screenpipe","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull requests: screenpipe/screenpipe","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"is:pr is:closed","depth":12,"on_screen":true,"value":"is:pr is:closed","help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Labels 43","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Labels","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"43","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Milestones 0","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Milestones","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"New pull request","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New pull request","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Clear current search query, filters, and sorts","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Clear current search query, filters, and sorts","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"17 Open","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17 Open","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1,593 Closed","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1,593 Closed","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Author","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Author","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Label","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Label","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Projects","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Projects","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Milestones","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Milestones","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Reviews","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Reviews","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Assignee","depth":12,"on_screen":true,"help_text":"Assignees","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Assignee","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Sort","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Sort","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull requests list","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull requests list","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add 3 recent regression test entries","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add 3 recent regression test entries","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3224 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"testing: update spec from recent changes (2026-05-04)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"testing: update spec from recent changes (2026-05-04)","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3223 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: add circuit breaker for corrupted segmentation model","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: add circuit breaker for corrupted segmentation model","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3222 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add a11y multi-line bbox regression entry","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add a11y multi-line bbox regression entry","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3221 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: add diagnostic logging for audio device configuration selection","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: add diagnostic logging for audio device configuration selection","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3220 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs: improve SEO titles across generic pages","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs: improve SEO titles across generic pages","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3219 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"on_screen":true,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"changelog: week of may 3, 2026","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"changelog: week of may 3, 2026","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3218 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"on_screen":true,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add multi-line text bbox capture regression test","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add multi-line text bbox capture regression test","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3217 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Windows GetWindowRect bounds regression test","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Windows GetWindowRect bounds regression test","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3216 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fix devcontainer cargo path","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fix devcontainer cargo path","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3214 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"julpel8","depth":14,"on_screen":true,"help_text":"pull requests opened by julpel8","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"julpel8","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Contributor","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix(settings): api key regenerate cancel, apply button, manual edit","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(settings): api key regenerate cancel, apply button, manual edit","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3212 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Anshgrover23","depth":14,"on_screen":true,"help_text":"pull requests opened by Anshgrover23","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Anshgrover23","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Contributor","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add VACUUM INTO snapshot regression entry","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add VACUUM INTO snapshot regression entry","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3211 by","depth":14,"bounds":{"left":0.47743055,"top":0.0,"width":0.0375,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51493055,"top":0.0,"width":0.04826389,"height":0.016666668},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51493055,"top":0.0,"width":0.04826389,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5704861,"top":0.0,"width":0.049652778,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.62743056,"top":0.0,"width":0.045833334,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.6732639,"top":0.0,"width":0.043055557,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.7190972,"top":0.0,"width":0.00625,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7253472,"top":0.0,"width":0.06284722,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7253472,"top":0.0,"width":0.06284722,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix(chat): allow input chip to be removed","depth":13,"bounds":{"left":0.47743055,"top":0.0,"width":0.2125,"height":0.02111111},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(chat): allow input chip to be removed","depth":14,"bounds":{"left":0.47743055,"top":0.0,"width":0.2125,"height":0.02111111},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3210 by","depth":14,"bounds":{"left":0.47743055,"top":0.0,"width":0.03888889,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"thisisharsh7","depth":14,"bounds":{"left":0.51631945,"top":0.0,"width":0.047222223,"height":0.016666668},"on_screen":true,"help_text":"pull requests opened by thisisharsh7","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"thisisharsh7","depth":15,"bounds":{"left":0.51631945,"top":0.0,"width":0.047222223,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Contributor","depth":16,"bounds":{"left":0.5708333,"top":0.0,"width":0.046180554,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.62430555,"top":0.0,"width":0.05,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"bounds":{"left":0.67430556,"top":0.0,"width":0.043055557,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.7201389,"top":0.0,"width":0.00625,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7263889,"top":0.0,"width":0.06284722,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7263889,"top":0.0,"width":0.06284722,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: graceful fallback when segmentation model cache is invalidated","depth":13,"bounds":{"left":0.47743055,"top":0.02111111,"width":0.35625,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: graceful fallback when segmentation model cache is invalidated","depth":14,"bounds":{"left":0.47743055,"top":0.02111111,"width":0.35625,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3209 by","depth":14,"bounds":{"left":0.47743055,"top":0.052222222,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51770836,"top":0.052222222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51770836,"top":0.052222222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5732639,"top":0.052222222,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.6302083,"top":0.052222222,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.67604166,"top":0.052222222,"width":0.043055557,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.721875,"top":0.05111111,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.728125,"top":0.05111111,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.728125,"top":0.05111111,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"testing: update spec from recent changes (2026-05-03)","depth":13,"bounds":{"left":0.47743055,"top":0.093888886,"width":0.29895833,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"testing: update spec from recent changes (2026-05-03)","depth":14,"bounds":{"left":0.47743055,"top":0.093888886,"width":0.29895833,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3208 by","depth":14,"bounds":{"left":0.47743055,"top":0.125,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51770836,"top":0.125,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51770836,"top":0.125,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5732639,"top":0.125,"width":0.05,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.6302083,"top":0.125,"width":0.046180554,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.67638886,"top":0.125,"width":0.042708334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.721875,"top":0.12388889,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.728125,"top":0.12388889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.728125,"top":0.12388889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add empty-state navigation button regression test","depth":13,"bounds":{"left":0.47743055,"top":0.16611111,"width":0.34305555,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add empty-state navigation button regression test","depth":14,"bounds":{"left":0.47743055,"top":0.16611111,"width":0.34305555,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3207 by","depth":14,"bounds":{"left":0.47743055,"top":0.19722222,"width":0.039583333,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.5170139,"top":0.19722222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.5170139,"top":0.19722222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.57256943,"top":0.19722222,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.62951386,"top":0.19722222,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.6753472,"top":0.19722222,"width":0.043055557,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.72118056,"top":0.19611111,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7274306,"top":0.19611111,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7274306,"top":0.19611111,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: audio dedup-skip metric — prevent false health check stalls","depth":13,"bounds":{"left":0.47743055,"top":0.23888889,"width":0.334375,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: audio dedup-skip metric — prevent false health check stalls","depth":14,"bounds":{"left":0.47743055,"top":0.23888889,"width":0.334375,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3206 by","depth":14,"bounds":{"left":0.47743055,"top":0.27,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51770836,"top":0.27,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51770836,"top":0.27,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5732639,"top":0.27,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.6302083,"top":0.27,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2 days ago","depth":15,"bounds":{"left":0.67604166,"top":0.27,"width":0.042708334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.72152776,"top":0.2688889,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7277778,"top":0.2688889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7277778,"top":0.2688889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"changelog: week of may 3, 2026","depth":13,"bounds":{"left":0.47743055,"top":0.31111112,"width":0.171875,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"changelog: week of may 3, 2026","depth":14,"bounds":{"left":0.47743055,"top":0.31111112,"width":0.171875,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3204 by","depth":14,"bounds":{"left":0.47743055,"top":0.3422222,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"bounds":{"left":0.51770836,"top":0.3422222,"width":0.028819444,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"bounds":{"left":0.51770836,"top":0.3422222,"width":0.028819444,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"bounds":{"left":0.5538194,"top":0.3422222,"width":0.013888889,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.57256943,"top":0.3422222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.62083334,"top":0.3422222,"width":0.042708334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.66631943,"top":0.34111112,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.67256945,"top":0.34111112,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.67256945,"top":0.34111112,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add per-line search highlight regression test","depth":13,"bounds":{"left":0.47743055,"top":0.3838889,"width":0.31111112,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add per-line search highlight regression test","depth":14,"bounds":{"left":0.47743055,"top":0.3838889,"width":0.31111112,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3203 by","depth":14,"bounds":{"left":0.47743055,"top":0.415,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51770836,"top":0.415,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51770836,"top":0.415,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5732639,"top":0.415,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.6302083,"top":0.415,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.67604166,"top":0.415,"width":0.043055557,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.721875,"top":0.4138889,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.728125,"top":0.4138889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.728125,"top":0.4138889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Apple Vision per-word OCR fast path regression test","depth":13,"bounds":{"left":0.47743055,"top":0.45666668,"width":0.37638888,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Apple Vision per-word OCR fast path regression test","depth":14,"bounds":{"left":0.47743055,"top":0.45666668,"width":0.37638888,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3202 by","depth":14,"bounds":{"left":0.47743055,"top":0.48777777,"width":0.039930556,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.5173611,"top":0.48777777,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.5173611,"top":0.48777777,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5729167,"top":0.48777777,"width":0.05,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.6298611,"top":0.48777777,"width":0.05,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"bounds":{"left":0.6798611,"top":0.48777777,"width":0.036805555,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.71944445,"top":0.48666668,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7256944,"top":0.48666668,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7256944,"top":0.48666668,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Windows AVX2 CPU support regression entry","depth":13,"bounds":{"left":0.47743055,"top":0.5288889,"width":0.3402778,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Windows AVX2 CPU support regression entry","depth":14,"bounds":{"left":0.47743055,"top":0.5288889,"width":0.3402778,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3201 by","depth":14,"bounds":{"left":0.47743055,"top":0.56,"width":0.03888889,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51631945,"top":0.56,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51631945,"top":0.56,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.571875,"top":0.56,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.62881947,"top":0.56,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"bounds":{"left":0.67465276,"top":0.56,"width":0.036805555,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.71423614,"top":0.5588889,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7204861,"top":0.5588889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7204861,"top":0.5588889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add timeline Escape key regression test for Windows","depth":13,"bounds":{"left":0.47743055,"top":0.6016667,"width":0.35555556,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add timeline Escape key regression test for Windows","depth":14,"bounds":{"left":0.47743055,"top":0.6016667,"width":0.35555556,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3200 by","depth":14,"bounds":{"left":0.47743055,"top":0.63277775,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51770836,"top":0.63277775,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51770836,"top":0.63277775,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5732639,"top":0.63277775,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.6302083,"top":0.63277775,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"bounds":{"left":0.67604166,"top":0.63277775,"width":0.036805555,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.715625,"top":0.63166666,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.721875,"top":0.63166666,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.721875,"top":0.63166666,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: preserve original db error in write queue instead of masking with PoolTimedOut","depth":13,"bounds":{"left":0.47743055,"top":0.67444444,"width":0.4375,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: preserve original db error in write queue instead of masking with PoolTimedOut","depth":14,"bounds":{"left":0.47743055,"top":0.67444444,"width":0.4375,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3199 by","depth":14,"bounds":{"left":0.47743055,"top":0.70555556,"width":0.03923611,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51666665,"top":0.70555556,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51666665,"top":0.70555556,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.57222223,"top":0.70555556,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.62916666,"top":0.70555556,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"bounds":{"left":0.675,"top":0.70555556,"width":0.036805555,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.71458334,"top":0.70444447,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.72083336,"top":0.70444447,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.72083336,"top":0.70444447,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"testing: update spec from recent changes (2026-05-02)","depth":13,"bounds":{"left":0.47743055,"top":0.74666667,"width":0.2986111,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"testing: update spec from recent changes (2026-05-02)","depth":14,"bounds":{"left":0.47743055,"top":0.74666667,"width":0.2986111,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3198 by","depth":14,"bounds":{"left":0.47743055,"top":0.7777778,"width":0.03923611,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51666665,"top":0.7777778,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51666665,"top":0.7777778,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.57222223,"top":0.7777778,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.62916666,"top":0.7777778,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"bounds":{"left":0.675,"top":0.7777778,"width":0.036805555,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.71458334,"top":0.77666664,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.72083336,"top":0.77666664,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.72083336,"top":0.77666664,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Bluetooth audio device hijack recovery regression test","depth":13,"bounds":{"left":0.47743055,"top":0.8194444,"width":0.3861111,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Bluetooth audio device hijack recovery regression test","depth":14,"bounds":{"left":0.47743055,"top":0.8194444,"width":0.3861111,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3197 by","depth":14,"bounds":{"left":0.47743055,"top":0.85055554,"width":0.038541667,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.5159722,"top":0.85055554,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.5159722,"top":0.85055554,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5715278,"top":0.85055554,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.6284722,"top":0.85055554,"width":0.05,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"bounds":{"left":0.6784722,"top":0.85055554,"width":0.036805555,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.71805555,"top":0.84944445,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.72430557,"top":0.84944445,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.72430557,"top":0.84944445,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Previous page","depth":11,"bounds":{"left":0.70555556,"top":0.8977778,"width":0.067708336,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Previous","depth":12,"bounds":{"left":0.7270833,"top":0.9061111,"width":0.038541667,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 1","depth":11,"bounds":{"left":0.7760417,"top":0.8977778,"width":0.022222223,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":12,"bounds":{"left":0.78506947,"top":0.9061111,"width":0.004166667,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":12,"bounds":{"left":0.8090278,"top":0.9061111,"width":0.005902778,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 3","depth":11,"bounds":{"left":0.82604164,"top":0.8977778,"width":0.022222223,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3","depth":12,"bounds":{"left":0.83402777,"top":0.9061111,"width":0.005902778,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 4","depth":11,"bounds":{"left":0.8510417,"top":0.8977778,"width":0.022222223,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4","depth":12,"bounds":{"left":0.8590278,"top":0.9061111,"width":0.005902778,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 5","depth":11,"bounds":{"left":0.87569445,"top":0.8977778,"width":0.022222223,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5","depth":12,"bounds":{"left":0.8840278,"top":0.9061111,"width":0.005902778,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"…","depth":12,"bounds":{"left":0.90833336,"top":0.9061111,"width":0.007638889,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 63","depth":11,"bounds":{"left":0.92638886,"top":0.8977778,"width":0.027430555,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"63","depth":12,"bounds":{"left":0.9340278,"top":0.9061111,"width":0.012152778,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 64","depth":11,"bounds":{"left":0.9565972,"top":0.8977778,"width":0.027430555,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"64","depth":12,"bounds":{"left":0.96423614,"top":0.9061111,"width":0.012152778,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Next page","depth":11,"bounds":{"left":0.98680556,"top":0.8977778,"width":0.013194442,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Next","depth":12,"bounds":{"left":0.99444443,"top":0.9061111,"width":0.00555557,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ProTip!","depth":12,"bounds":{"left":0.7434028,"top":0.9533333,"width":0.032986112,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Adding","depth":11,"bounds":{"left":0.7763889,"top":0.9533333,"width":0.036805555,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"no:label","depth":11,"bounds":{"left":0.81319445,"top":0.9533333,"width":0.035416666,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"no:label","depth":12,"bounds":{"left":0.81319445,"top":0.9533333,"width":0.035416666,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"will show everything without a label.","depth":11,"bounds":{"left":0.8486111,"top":0.9533333,"width":0.15138888,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Footer","depth":7,"bounds":{"left":0.22916667,"top":1.0,"width":0.00069444446,"height":-0.027777791},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Footer","depth":8,"bounds":{"left":0.22916667,"top":1.0,"width":0.048958335,"height":-0.031666636},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub Homepage","depth":7,"bounds":{"left":0.56180555,"top":1.0,"width":0.016666668,"height":-0.027777791},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"© 2026 GitHub, Inc.","depth":8,"bounds":{"left":0.58402777,"top":1.0,"width":0.079166666,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Footer navigation","depth":8,"bounds":{"left":0.66875,"top":1.0,"width":0.00069444446,"height":-0.031666636},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Footer navigation","depth":9,"bounds":{"left":0.66875,"top":1.0,"width":0.06666667,"height":-0.034999967},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Terms","depth":10,"bounds":{"left":0.67430556,"top":1.0,"width":0.024305556,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Terms","depth":11,"bounds":{"left":0.67430556,"top":1.0,"width":0.024305556,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Privacy","depth":10,"bounds":{"left":0.7097222,"top":1.0,"width":0.028472222,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Privacy","depth":11,"bounds":{"left":0.7097222,"top":1.0,"width":0.028472222,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security","depth":10,"bounds":{"left":0.74930555,"top":1.0,"width":0.03263889,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security","depth":11,"bounds":{"left":0.74930555,"top":1.0,"width":0.03263889,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Status","depth":10,"bounds":{"left":0.79305553,"top":1.0,"width":0.025,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Status","depth":11,"bounds":{"left":0.79305553,"top":1.0,"width":0.025,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Community","depth":10,"bounds":{"left":0.82916665,"top":1.0,"width":0.044791665,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Community","depth":11,"bounds":{"left":0.82916665,"top":1.0,"width":0.044791665,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Docs","depth":10,"bounds":{"left":0.88506943,"top":1.0,"width":0.02013889,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Docs","depth":11,"bounds":{"left":0.88506943,"top":1.0,"width":0.02013889,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Contact","depth":10,"bounds":{"left":0.91631943,"top":1.0,"width":0.030902777,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Contact","depth":11,"bounds":{"left":0.91631943,"top":1.0,"width":0.030902777,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Manage cookies","depth":11,"bounds":{"left":0.9583333,"top":1.0,"width":0.041666687,"height":-0.031666636},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Do not share my personal information","depth":11,"bounds":{"left":1.0,"top":1.0,"width":-0.0333333,"height":-0.031666636},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-3904702670430433497
|
-4628629997471850852
|
visual_change
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Close tab
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to content
Skip to content
Navigation Menu
Navigation Menu
Homepage
Platform
Solutions
Resources
Open Source
Enterprise
Pricing
Pricing
Search or jump to…
Search or jump to...
Sign in
Sign in
Sign up
Sign up
Appearance settings
screenpipe
screenpipe
/
screenpipe
screenpipe
Public
You must be signed in to change notification settings
Notifications
Fork 1.7k
Fork
1.7k
You must be signed in to star a repository
Star
18.6k
Code
Code
Issues 16
Issues
16
Pull requests 17
Pull requests
17
Discussions
Discussions
Actions
Actions
Projects
Projects
Security and quality
Security and quality
Insights
Insights
Pull requests: screenpipe/screenpipe
Pull requests: screenpipe/screenpipe
is:pr is:closed
Labels 43
Labels
43
Milestones 0
Milestones
0
New pull request
New pull request
Clear current search query, filters, and sorts
Clear current search query, filters, and sorts
17 Open
17 Open
1,593 Closed
1,593 Closed
Author
Author
Label
Label
Projects
Projects
Milestones
Milestones
Reviews
Reviews
Assignee
Assignee
Sort
Sort
Pull requests list
Pull requests list
docs(testing): add 3 recent regression test entries
docs(testing): add 3 recent regression test entries
#3224 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
testing: update spec from recent changes (2026-05-04)
testing: update spec from recent changes (2026-05-04)
#3223 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add circuit breaker for corrupted segmentation model
fix: add circuit breaker for corrupted segmentation model
#3222 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add a11y multi-line bbox regression entry
docs(testing): add a11y multi-line bbox regression entry
#3221 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add diagnostic logging for audio device configuration selection
fix: add diagnostic logging for audio device configuration selection
#3220 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs: improve SEO titles across generic pages
docs: improve SEO titles across generic pages
#3219 by
mintlify
mintlify
Bot
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3218 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add multi-line text bbox capture regression test
docs(testing): add multi-line text bbox capture regression test
#3217 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Windows GetWindowRect bounds regression test
docs(testing): add Windows GetWindowRect bounds regression test
#3216 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
Fix devcontainer cargo path
Fix devcontainer cargo path
#3214 by
julpel8
julpel8
Contributor
was merged
4 days ago
•
Review required before merging
Review required
fix(settings): api key regenerate cancel, apply button, manual edit
fix(settings): api key regenerate cancel, apply button, manual edit
#3212 by
Anshgrover23
Anshgrover23
Contributor
was merged
5 days ago
•
Review required before merging
Review required
docs(testing): add VACUUM INTO snapshot regression entry
docs(testing): add VACUUM INTO snapshot regression entry
#3211 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix(chat): allow input chip to be removed
fix(chat): allow input chip to be removed
#3210 by
thisisharsh7
thisisharsh7
Contributor
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
fix: graceful fallback when segmentation model cache is invalidated
fix: graceful fallback when segmentation model cache is invalidated
#3209 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
testing: update spec from recent changes (2026-05-03)
testing: update spec from recent changes (2026-05-03)
#3208 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add empty-state navigation button regression test
docs(testing): add empty-state navigation button regression test
#3207 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: audio dedup-skip metric — prevent false health check stalls
fix: audio dedup-skip metric — prevent false health check stalls
#3206 by
louis030195
louis030195
Collaborator
was closed
2 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3204 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add per-line search highlight regression test
docs(testing): add per-line search highlight regression test
#3203 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Apple Vision per-word OCR fast path regression test
docs(testing): add Apple Vision per-word OCR fast path regression test
#3202 by
louis030195
louis030195
Collaborator
was merged
last week
•
Review required before merging
Review required
docs(testing): add Windows AVX2 CPU support regression entry
docs(testing): add Windows AVX2 CPU support regression entry
#3201 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
docs(testing): add timeline Escape key regression test for Windows
docs(testing): add timeline Escape key regression test for Windows
#3200 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
fix: preserve original db error in write queue instead of masking with PoolTimedOut
fix: preserve original db error in write queue instead of masking with PoolTimedOut
#3199 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
testing: update spec from recent changes (2026-05-02)
testing: update spec from recent changes (2026-05-02)
#3198 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
docs(testing): add Bluetooth audio device hijack recovery regression test
docs(testing): add Bluetooth audio device hijack recovery regression test
#3197 by
louis030195
louis030195
Collaborator
was merged
last week
•
Review required before merging
Review required
Previous page
Previous
Page 1
1
2
Page 3
3
Page 4
4
Page 5
5
…
Page 63
63
Page 64
64
Next page
Next
ProTip!
Adding
no:label
no:label
will show everything without a label.
Footer
Footer
GitHub Homepage
© 2026 GitHub, Inc.
Footer navigation
Footer navigation
Terms
Terms
Privacy
Privacy
Security
Security
Status
Status
Community
Community
Docs
Docs
Contact
Contact
Manage cookies
Do not share my personal information...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10192
|
467
|
4
|
2026-05-08T17:10:33.011814+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260233011_m1.jpg...
|
Firefox
|
Pull requests · screenpipe/screenpipe · GitHub — P Pull requests · screenpipe/screenpipe · GitHub — Personal...
|
1
|
github.com/screenpipe/screenpipe/pulls?page=2& github.com/screenpipe/screenpipe/pulls?page=2&q=is%3Apr+is%3Aclosed...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Screenpipe — Archive
[IP_ADDRESS]
Pull requests · Screenpipe — Archive
[IP_ADDRESS]
Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Close tab
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
Close tab
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to content
Skip to content
Navigation Menu
Navigation Menu
Homepage
Platform
Solutions
Resources
Open Source
Enterprise
Pricing
Pricing
Search or jump to…
Search or jump to...
Sign in
Sign in
Sign up
Sign up
Appearance settings
screenpipe
screenpipe
/
screenpipe
screenpipe
Public
You must be signed in to change notification settings
Notifications
Fork 1.7k
Fork
1.7k
You must be signed in to star a repository
Star
18.6k
Code
Code
Issues 16
Issues
16
Pull requests 17
Pull requests
17
Discussions
Discussions
Actions
Actions
Projects
Projects
Security and quality
Security and quality
Insights
Insights
Pull requests: screenpipe/screenpipe
Pull requests: screenpipe/screenpipe
is:pr is:closed
Labels 43
Labels
43
Milestones 0
Milestones
0
New pull request
New pull request
Clear current search query, filters, and sorts
Clear current search query, filters, and sorts
17 Open
17 Open
1,593 Closed
1,593 Closed
Author
Author
Label
Label
Projects
Projects
Milestones
Milestones
Reviews
Reviews
Assignee
Assignee
Sort
Sort
Pull requests list
Pull requests list
docs(testing): add 3 recent regression test entries
docs(testing): add 3 recent regression test entries
#3224 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
testing: update spec from recent changes (2026-05-04)
testing: update spec from recent changes (2026-05-04)
#3223 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add circuit breaker for corrupted segmentation model
fix: add circuit breaker for corrupted segmentation model
#3222 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add a11y multi-line bbox regression entry
docs(testing): add a11y multi-line bbox regression entry
#3221 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add diagnostic logging for audio device configuration selection
fix: add diagnostic logging for audio device configuration selection
#3220 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs: improve SEO titles across generic pages
docs: improve SEO titles across generic pages
#3219 by
mintlify
mintlify
Bot
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3218 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add multi-line text bbox capture regression test
docs(testing): add multi-line text bbox capture regression test
#3217 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Windows GetWindowRect bounds regression test
docs(testing): add Windows GetWindowRect bounds regression test
#3216 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
Fix devcontainer cargo path
Fix devcontainer cargo path
#3214 by
julpel8
julpel8
Contributor
was merged
4 days ago
•
Review required before merging
Review required
fix(settings): api key regenerate cancel, apply button, manual edit
fix(settings): api key regenerate cancel, apply button, manual edit
#3212 by
Anshgrover23
Anshgrover23
Contributor
was merged
5 days ago
•
Review required before merging
Review required
docs(testing): add VACUUM INTO snapshot regression entry
docs(testing): add VACUUM INTO snapshot regression entry
#3211 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix(chat): allow input chip to be removed
fix(chat): allow input chip to be removed
#3210 by
thisisharsh7
thisisharsh7
Contributor
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
fix: graceful fallback when segmentation model cache is invalidated
fix: graceful fallback when segmentation model cache is invalidated
#3209 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
testing: update spec from recent changes (2026-05-03)
testing: update spec from recent changes (2026-05-03)
#3208 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add empty-state navigation button regression test
docs(testing): add empty-state navigation button regression test
#3207 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: audio dedup-skip metric — prevent false health check stalls
fix: audio dedup-skip metric — prevent false health check stalls
#3206 by
louis030195
louis030195
Collaborator
was closed
2 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3204 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add per-line search highlight regression test
docs(testing): add per-line search highlight regression test
#3203 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Apple Vision per-word OCR fast path regression test
docs(testing): add Apple Vision per-word OCR fast path regression test
#3202 by
louis030195
louis030195
Collaborator
was merged
last week
•
Review required before merging
Review required
docs(testing): add Windows AVX2 CPU support regression entry
docs(testing): add Windows AVX2 CPU support regression entry
#3201 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
docs(testing): add timeline Escape key regression test for Windows
docs(testing): add timeline Escape key regression test for Windows
#3200 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
fix: preserve original db error in write queue instead of masking with PoolTimedOut
fix: preserve original db error in write queue instead of masking with PoolTimedOut
#3199 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
testing: update spec from recent changes (2026-05-02)
testing: update spec from recent changes (2026-05-02)
#3198 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
docs(testing): add Bluetooth audio device hijack recovery regression test
docs(testing): add Bluetooth audio device hijack recovery regression test
#3197 by
louis030195
louis030195
Collaborator
was merged
last week
•
Review required before merging
Review required
Previous page
Previous
Page 1
1
2
Page 3
3
Page 4
4
Page 5
5
…
Page 63
63
Page 64
64
Next page
Next
ProTip!
Adding
no:label
no:label
will show everything without a label.
Footer
Footer
GitHub Homepage
© 2026 GitHub, Inc.
Footer navigation
Footer navigation
Terms
Terms
Privacy
Privacy
Security
Security
Status
Status
Community
Community
Docs
Docs
Contact
Contact
Manage cookies
Do not share my personal information...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"192.168.0.242","depth":4,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.009375,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.03263889,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.05590278,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.079166666,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to content","depth":6,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Navigation Menu","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Navigation Menu","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Homepage","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Platform","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Solutions","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Resources","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Source","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Enterprise","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Pricing","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pricing","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search or jump to...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sign in","depth":8,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sign in","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sign up","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sign up","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Appearance settings","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"screenpipe","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"screenpipe","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"You must be signed in to change notification settings","depth":11,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fork 1.7k","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fork","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1.7k","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"You must be signed in to star a repository","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Star","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18.6k","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Issues 16","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests 17","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Discussions","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Discussions","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Projects","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Projects","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull requests: screenpipe/screenpipe","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull requests: screenpipe/screenpipe","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"is:pr is:closed","depth":12,"on_screen":true,"value":"is:pr is:closed","help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Labels 43","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Labels","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"43","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Milestones 0","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Milestones","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"New pull request","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New pull request","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Clear current search query, filters, and sorts","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Clear current search query, filters, and sorts","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"17 Open","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17 Open","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1,593 Closed","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1,593 Closed","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Author","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Author","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Label","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Label","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Projects","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Projects","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Milestones","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Milestones","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Reviews","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Reviews","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Assignee","depth":12,"on_screen":true,"help_text":"Assignees","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Assignee","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Sort","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Sort","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull requests list","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull requests list","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add 3 recent regression test entries","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add 3 recent regression test entries","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3224 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"testing: update spec from recent changes (2026-05-04)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"testing: update spec from recent changes (2026-05-04)","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3223 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: add circuit breaker for corrupted segmentation model","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: add circuit breaker for corrupted segmentation model","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3222 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add a11y multi-line bbox regression entry","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add a11y multi-line bbox regression entry","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3221 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: add diagnostic logging for audio device configuration selection","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: add diagnostic logging for audio device configuration selection","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3220 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs: improve SEO titles across generic pages","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs: improve SEO titles across generic pages","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3219 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"on_screen":true,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"changelog: week of may 3, 2026","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"changelog: week of may 3, 2026","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3218 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"on_screen":true,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add multi-line text bbox capture regression test","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add multi-line text bbox capture regression test","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3217 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Windows GetWindowRect bounds regression test","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Windows GetWindowRect bounds regression test","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3216 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fix devcontainer cargo path","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fix devcontainer cargo path","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3214 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"julpel8","depth":14,"on_screen":true,"help_text":"pull requests opened by julpel8","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"julpel8","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Contributor","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix(settings): api key regenerate cancel, apply button, manual edit","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(settings): api key regenerate cancel, apply button, manual edit","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3212 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Anshgrover23","depth":14,"on_screen":true,"help_text":"pull requests opened by Anshgrover23","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Anshgrover23","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Contributor","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add VACUUM INTO snapshot regression entry","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add VACUUM INTO snapshot regression entry","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3211 by","depth":14,"bounds":{"left":0.47743055,"top":0.0,"width":0.0375,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51493055,"top":0.0,"width":0.04826389,"height":0.016666668},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51493055,"top":0.0,"width":0.04826389,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5704861,"top":0.0,"width":0.049652778,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.62743056,"top":0.0,"width":0.045833334,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.6732639,"top":0.0,"width":0.043055557,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.7190972,"top":0.0,"width":0.00625,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7253472,"top":0.0,"width":0.06284722,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7253472,"top":0.0,"width":0.06284722,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix(chat): allow input chip to be removed","depth":13,"bounds":{"left":0.47743055,"top":0.0,"width":0.2125,"height":0.02111111},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(chat): allow input chip to be removed","depth":14,"bounds":{"left":0.47743055,"top":0.0,"width":0.2125,"height":0.02111111},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3210 by","depth":14,"bounds":{"left":0.47743055,"top":0.0,"width":0.03888889,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"thisisharsh7","depth":14,"bounds":{"left":0.51631945,"top":0.0,"width":0.047222223,"height":0.016666668},"on_screen":true,"help_text":"pull requests opened by thisisharsh7","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"thisisharsh7","depth":15,"bounds":{"left":0.51631945,"top":0.0,"width":0.047222223,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Contributor","depth":16,"bounds":{"left":0.5708333,"top":0.0,"width":0.046180554,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.62430555,"top":0.0,"width":0.05,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"bounds":{"left":0.67430556,"top":0.0,"width":0.043055557,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.7201389,"top":0.0,"width":0.00625,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7263889,"top":0.0,"width":0.06284722,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7263889,"top":0.0,"width":0.06284722,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: graceful fallback when segmentation model cache is invalidated","depth":13,"bounds":{"left":0.47743055,"top":0.02111111,"width":0.35625,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: graceful fallback when segmentation model cache is invalidated","depth":14,"bounds":{"left":0.47743055,"top":0.02111111,"width":0.35625,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3209 by","depth":14,"bounds":{"left":0.47743055,"top":0.052222222,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51770836,"top":0.052222222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51770836,"top":0.052222222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5732639,"top":0.052222222,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.6302083,"top":0.052222222,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.67604166,"top":0.052222222,"width":0.043055557,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.721875,"top":0.05111111,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.728125,"top":0.05111111,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.728125,"top":0.05111111,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"testing: update spec from recent changes (2026-05-03)","depth":13,"bounds":{"left":0.47743055,"top":0.093888886,"width":0.29895833,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"testing: update spec from recent changes (2026-05-03)","depth":14,"bounds":{"left":0.47743055,"top":0.093888886,"width":0.29895833,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3208 by","depth":14,"bounds":{"left":0.47743055,"top":0.125,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51770836,"top":0.125,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51770836,"top":0.125,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5732639,"top":0.125,"width":0.05,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.6302083,"top":0.125,"width":0.046180554,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.67638886,"top":0.125,"width":0.042708334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.721875,"top":0.12388889,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.728125,"top":0.12388889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.728125,"top":0.12388889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add empty-state navigation button regression test","depth":13,"bounds":{"left":0.47743055,"top":0.16611111,"width":0.34305555,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add empty-state navigation button regression test","depth":14,"bounds":{"left":0.47743055,"top":0.16611111,"width":0.34305555,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3207 by","depth":14,"bounds":{"left":0.47743055,"top":0.19722222,"width":0.039583333,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.5170139,"top":0.19722222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.5170139,"top":0.19722222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.57256943,"top":0.19722222,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.62951386,"top":0.19722222,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.6753472,"top":0.19722222,"width":0.043055557,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.72118056,"top":0.19611111,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7274306,"top":0.19611111,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7274306,"top":0.19611111,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: audio dedup-skip metric — prevent false health check stalls","depth":13,"bounds":{"left":0.47743055,"top":0.23888889,"width":0.334375,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: audio dedup-skip metric — prevent false health check stalls","depth":14,"bounds":{"left":0.47743055,"top":0.23888889,"width":0.334375,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3206 by","depth":14,"bounds":{"left":0.47743055,"top":0.27,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51770836,"top":0.27,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51770836,"top":0.27,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5732639,"top":0.27,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.6302083,"top":0.27,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2 days ago","depth":15,"bounds":{"left":0.67604166,"top":0.27,"width":0.042708334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.72152776,"top":0.2688889,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7277778,"top":0.2688889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7277778,"top":0.2688889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"changelog: week of may 3, 2026","depth":13,"bounds":{"left":0.47743055,"top":0.31111112,"width":0.171875,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"changelog: week of may 3, 2026","depth":14,"bounds":{"left":0.47743055,"top":0.31111112,"width":0.171875,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3204 by","depth":14,"bounds":{"left":0.47743055,"top":0.3422222,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"bounds":{"left":0.51770836,"top":0.3422222,"width":0.028819444,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"bounds":{"left":0.51770836,"top":0.3422222,"width":0.028819444,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"bounds":{"left":0.5538194,"top":0.3422222,"width":0.013888889,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.57256943,"top":0.3422222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.62083334,"top":0.3422222,"width":0.042708334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.66631943,"top":0.34111112,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.67256945,"top":0.34111112,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.67256945,"top":0.34111112,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add per-line search highlight regression test","depth":13,"bounds":{"left":0.47743055,"top":0.3838889,"width":0.31111112,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add per-line search highlight regression test","depth":14,"bounds":{"left":0.47743055,"top":0.3838889,"width":0.31111112,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3203 by","depth":14,"bounds":{"left":0.47743055,"top":0.415,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51770836,"top":0.415,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51770836,"top":0.415,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5732639,"top":0.415,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.6302083,"top":0.415,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.67604166,"top":0.415,"width":0.043055557,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.721875,"top":0.4138889,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.728125,"top":0.4138889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.728125,"top":0.4138889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Apple Vision per-word OCR fast path regression test","depth":13,"bounds":{"left":0.47743055,"top":0.45666668,"width":0.37638888,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Apple Vision per-word OCR fast path regression test","depth":14,"bounds":{"left":0.47743055,"top":0.45666668,"width":0.37638888,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3202 by","depth":14,"bounds":{"left":0.47743055,"top":0.48777777,"width":0.039930556,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.5173611,"top":0.48777777,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.5173611,"top":0.48777777,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5729167,"top":0.48777777,"width":0.05,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.6298611,"top":0.48777777,"width":0.05,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"bounds":{"left":0.6798611,"top":0.48777777,"width":0.036805555,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.71944445,"top":0.48666668,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7256944,"top":0.48666668,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7256944,"top":0.48666668,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Windows AVX2 CPU support regression entry","depth":13,"bounds":{"left":0.47743055,"top":0.5288889,"width":0.3402778,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Windows AVX2 CPU support regression entry","depth":14,"bounds":{"left":0.47743055,"top":0.5288889,"width":0.3402778,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3201 by","depth":14,"bounds":{"left":0.47743055,"top":0.56,"width":0.03888889,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51631945,"top":0.56,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51631945,"top":0.56,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.571875,"top":0.56,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.62881947,"top":0.56,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"bounds":{"left":0.67465276,"top":0.56,"width":0.036805555,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.71423614,"top":0.5588889,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7204861,"top":0.5588889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7204861,"top":0.5588889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add timeline Escape key regression test for Windows","depth":13,"bounds":{"left":0.47743055,"top":0.6016667,"width":0.35555556,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add timeline Escape key regression test for Windows","depth":14,"bounds":{"left":0.47743055,"top":0.6016667,"width":0.35555556,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3200 by","depth":14,"bounds":{"left":0.47743055,"top":0.63277775,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51770836,"top":0.63277775,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51770836,"top":0.63277775,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5732639,"top":0.63277775,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.6302083,"top":0.63277775,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"bounds":{"left":0.67604166,"top":0.63277775,"width":0.036805555,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.715625,"top":0.63166666,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.721875,"top":0.63166666,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.721875,"top":0.63166666,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: preserve original db error in write queue instead of masking with PoolTimedOut","depth":13,"bounds":{"left":0.47743055,"top":0.67444444,"width":0.4375,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: preserve original db error in write queue instead of masking with PoolTimedOut","depth":14,"bounds":{"left":0.47743055,"top":0.67444444,"width":0.4375,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3199 by","depth":14,"bounds":{"left":0.47743055,"top":0.70555556,"width":0.03923611,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51666665,"top":0.70555556,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51666665,"top":0.70555556,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.57222223,"top":0.70555556,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.62916666,"top":0.70555556,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"bounds":{"left":0.675,"top":0.70555556,"width":0.036805555,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.71458334,"top":0.70444447,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.72083336,"top":0.70444447,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.72083336,"top":0.70444447,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"testing: update spec from recent changes (2026-05-02)","depth":13,"bounds":{"left":0.47743055,"top":0.74666667,"width":0.2986111,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"testing: update spec from recent changes (2026-05-02)","depth":14,"bounds":{"left":0.47743055,"top":0.74666667,"width":0.2986111,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3198 by","depth":14,"bounds":{"left":0.47743055,"top":0.7777778,"width":0.03923611,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51666665,"top":0.7777778,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51666665,"top":0.7777778,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.57222223,"top":0.7777778,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.62916666,"top":0.7777778,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"bounds":{"left":0.675,"top":0.7777778,"width":0.036805555,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.71458334,"top":0.77666664,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.72083336,"top":0.77666664,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.72083336,"top":0.77666664,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Bluetooth audio device hijack recovery regression test","depth":13,"bounds":{"left":0.47743055,"top":0.8194444,"width":0.3861111,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Bluetooth audio device hijack recovery regression test","depth":14,"bounds":{"left":0.47743055,"top":0.8194444,"width":0.3861111,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3197 by","depth":14,"bounds":{"left":0.47743055,"top":0.85055554,"width":0.038541667,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.5159722,"top":0.85055554,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.5159722,"top":0.85055554,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5715278,"top":0.85055554,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.6284722,"top":0.85055554,"width":0.05,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"bounds":{"left":0.6784722,"top":0.85055554,"width":0.036805555,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.71805555,"top":0.84944445,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.72430557,"top":0.84944445,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.72430557,"top":0.84944445,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Previous page","depth":11,"bounds":{"left":0.70555556,"top":0.8977778,"width":0.067708336,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Previous","depth":12,"bounds":{"left":0.7270833,"top":0.9061111,"width":0.038541667,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 1","depth":11,"bounds":{"left":0.7760417,"top":0.8977778,"width":0.022222223,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":12,"bounds":{"left":0.78506947,"top":0.9061111,"width":0.004166667,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":12,"bounds":{"left":0.8090278,"top":0.9061111,"width":0.005902778,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 3","depth":11,"bounds":{"left":0.82604164,"top":0.8977778,"width":0.022222223,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3","depth":12,"bounds":{"left":0.83402777,"top":0.9061111,"width":0.005902778,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 4","depth":11,"bounds":{"left":0.8510417,"top":0.8977778,"width":0.022222223,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4","depth":12,"bounds":{"left":0.8590278,"top":0.9061111,"width":0.005902778,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 5","depth":11,"bounds":{"left":0.87569445,"top":0.8977778,"width":0.022222223,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5","depth":12,"bounds":{"left":0.8840278,"top":0.9061111,"width":0.005902778,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"…","depth":12,"bounds":{"left":0.90833336,"top":0.9061111,"width":0.007638889,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 63","depth":11,"bounds":{"left":0.92638886,"top":0.8977778,"width":0.027430555,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"63","depth":12,"bounds":{"left":0.9340278,"top":0.9061111,"width":0.012152778,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 64","depth":11,"bounds":{"left":0.9565972,"top":0.8977778,"width":0.027430555,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"64","depth":12,"bounds":{"left":0.96423614,"top":0.9061111,"width":0.012152778,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Next page","depth":11,"bounds":{"left":0.98680556,"top":0.8977778,"width":0.013194442,"height":0.035555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Next","depth":12,"bounds":{"left":0.99444443,"top":0.9061111,"width":0.00555557,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ProTip!","depth":12,"bounds":{"left":0.7434028,"top":0.9533333,"width":0.032986112,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Adding","depth":11,"bounds":{"left":0.7763889,"top":0.9533333,"width":0.036805555,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"no:label","depth":11,"bounds":{"left":0.81319445,"top":0.9533333,"width":0.035416666,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"no:label","depth":12,"bounds":{"left":0.81319445,"top":0.9533333,"width":0.035416666,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"will show everything without a label.","depth":11,"bounds":{"left":0.8486111,"top":0.9533333,"width":0.15138888,"height":0.018888889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Footer","depth":7,"bounds":{"left":0.22916667,"top":1.0,"width":0.00069444446,"height":-0.027777791},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Footer","depth":8,"bounds":{"left":0.22916667,"top":1.0,"width":0.048958335,"height":-0.031666636},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub Homepage","depth":7,"bounds":{"left":0.56180555,"top":1.0,"width":0.016666668,"height":-0.027777791},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"© 2026 GitHub, Inc.","depth":8,"bounds":{"left":0.58402777,"top":1.0,"width":0.079166666,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Footer navigation","depth":8,"bounds":{"left":0.66875,"top":1.0,"width":0.00069444446,"height":-0.031666636},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Footer navigation","depth":9,"bounds":{"left":0.66875,"top":1.0,"width":0.06666667,"height":-0.034999967},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Terms","depth":10,"bounds":{"left":0.67430556,"top":1.0,"width":0.024305556,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Terms","depth":11,"bounds":{"left":0.67430556,"top":1.0,"width":0.024305556,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Privacy","depth":10,"bounds":{"left":0.7097222,"top":1.0,"width":0.028472222,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Privacy","depth":11,"bounds":{"left":0.7097222,"top":1.0,"width":0.028472222,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security","depth":10,"bounds":{"left":0.74930555,"top":1.0,"width":0.03263889,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security","depth":11,"bounds":{"left":0.74930555,"top":1.0,"width":0.03263889,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Status","depth":10,"bounds":{"left":0.79305553,"top":1.0,"width":0.025,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Status","depth":11,"bounds":{"left":0.79305553,"top":1.0,"width":0.025,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Community","depth":10,"bounds":{"left":0.82916665,"top":1.0,"width":0.044791665,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Community","depth":11,"bounds":{"left":0.82916665,"top":1.0,"width":0.044791665,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Docs","depth":10,"bounds":{"left":0.88506943,"top":1.0,"width":0.02013889,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Docs","depth":11,"bounds":{"left":0.88506943,"top":1.0,"width":0.02013889,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Contact","depth":10,"bounds":{"left":0.91631943,"top":1.0,"width":0.030902777,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Contact","depth":11,"bounds":{"left":0.91631943,"top":1.0,"width":0.030902777,"height":-0.0333333},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Manage cookies","depth":11,"bounds":{"left":0.9583333,"top":1.0,"width":0.041666687,"height":-0.031666636},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Do not share my personal information","depth":11,"bounds":{"left":1.0,"top":1.0,"width":-0.0333333,"height":-0.031666636},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-3634706398058112898
|
-4772745185547706724
|
visual_change
|
accessibility
|
NULL
|
Screenpipe — Archive
[IP_ADDRESS]
Pull requests · Screenpipe — Archive
[IP_ADDRESS]
Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Close tab
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
Close tab
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to content
Skip to content
Navigation Menu
Navigation Menu
Homepage
Platform
Solutions
Resources
Open Source
Enterprise
Pricing
Pricing
Search or jump to…
Search or jump to...
Sign in
Sign in
Sign up
Sign up
Appearance settings
screenpipe
screenpipe
/
screenpipe
screenpipe
Public
You must be signed in to change notification settings
Notifications
Fork 1.7k
Fork
1.7k
You must be signed in to star a repository
Star
18.6k
Code
Code
Issues 16
Issues
16
Pull requests 17
Pull requests
17
Discussions
Discussions
Actions
Actions
Projects
Projects
Security and quality
Security and quality
Insights
Insights
Pull requests: screenpipe/screenpipe
Pull requests: screenpipe/screenpipe
is:pr is:closed
Labels 43
Labels
43
Milestones 0
Milestones
0
New pull request
New pull request
Clear current search query, filters, and sorts
Clear current search query, filters, and sorts
17 Open
17 Open
1,593 Closed
1,593 Closed
Author
Author
Label
Label
Projects
Projects
Milestones
Milestones
Reviews
Reviews
Assignee
Assignee
Sort
Sort
Pull requests list
Pull requests list
docs(testing): add 3 recent regression test entries
docs(testing): add 3 recent regression test entries
#3224 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
testing: update spec from recent changes (2026-05-04)
testing: update spec from recent changes (2026-05-04)
#3223 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add circuit breaker for corrupted segmentation model
fix: add circuit breaker for corrupted segmentation model
#3222 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add a11y multi-line bbox regression entry
docs(testing): add a11y multi-line bbox regression entry
#3221 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add diagnostic logging for audio device configuration selection
fix: add diagnostic logging for audio device configuration selection
#3220 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs: improve SEO titles across generic pages
docs: improve SEO titles across generic pages
#3219 by
mintlify
mintlify
Bot
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3218 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add multi-line text bbox capture regression test
docs(testing): add multi-line text bbox capture regression test
#3217 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Windows GetWindowRect bounds regression test
docs(testing): add Windows GetWindowRect bounds regression test
#3216 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
Fix devcontainer cargo path
Fix devcontainer cargo path
#3214 by
julpel8
julpel8
Contributor
was merged
4 days ago
•
Review required before merging
Review required
fix(settings): api key regenerate cancel, apply button, manual edit
fix(settings): api key regenerate cancel, apply button, manual edit
#3212 by
Anshgrover23
Anshgrover23
Contributor
was merged
5 days ago
•
Review required before merging
Review required
docs(testing): add VACUUM INTO snapshot regression entry
docs(testing): add VACUUM INTO snapshot regression entry
#3211 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix(chat): allow input chip to be removed
fix(chat): allow input chip to be removed
#3210 by
thisisharsh7
thisisharsh7
Contributor
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
fix: graceful fallback when segmentation model cache is invalidated
fix: graceful fallback when segmentation model cache is invalidated
#3209 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
testing: update spec from recent changes (2026-05-03)
testing: update spec from recent changes (2026-05-03)
#3208 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add empty-state navigation button regression test
docs(testing): add empty-state navigation button regression test
#3207 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: audio dedup-skip metric — prevent false health check stalls
fix: audio dedup-skip metric — prevent false health check stalls
#3206 by
louis030195
louis030195
Collaborator
was closed
2 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3204 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add per-line search highlight regression test
docs(testing): add per-line search highlight regression test
#3203 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Apple Vision per-word OCR fast path regression test
docs(testing): add Apple Vision per-word OCR fast path regression test
#3202 by
louis030195
louis030195
Collaborator
was merged
last week
•
Review required before merging
Review required
docs(testing): add Windows AVX2 CPU support regression entry
docs(testing): add Windows AVX2 CPU support regression entry
#3201 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
docs(testing): add timeline Escape key regression test for Windows
docs(testing): add timeline Escape key regression test for Windows
#3200 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
fix: preserve original db error in write queue instead of masking with PoolTimedOut
fix: preserve original db error in write queue instead of masking with PoolTimedOut
#3199 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
testing: update spec from recent changes (2026-05-02)
testing: update spec from recent changes (2026-05-02)
#3198 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
docs(testing): add Bluetooth audio device hijack recovery regression test
docs(testing): add Bluetooth audio device hijack recovery regression test
#3197 by
louis030195
louis030195
Collaborator
was merged
last week
•
Review required before merging
Review required
Previous page
Previous
Page 1
1
2
Page 3
3
Page 4
4
Page 5
5
…
Page 63
63
Page 64
64
Next page
Next
ProTip!
Adding
no:label
no:label
will show everything without a label.
Footer
Footer
GitHub Homepage
© 2026 GitHub, Inc.
Footer navigation
Footer navigation
Terms
Terms
Privacy
Privacy
Security
Security
Status
Status
Community
Community
Docs
Docs
Contact
Contact
Manage cookies
Do not share my personal information...
|
10190
|
NULL
|
NULL
|
NULL
|
|
10191
|
468
|
3
|
2026-05-08T17:10:32.668953+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260232668_m2.jpg...
|
Firefox
|
Pull requests · screenpipe/screenpipe · GitHub — P Pull requests · screenpipe/screenpipe · GitHub — Personal...
|
1
|
github.com/screenpipe/screenpipe/pulls?page=2& github.com/screenpipe/screenpipe/pulls?page=2&q=is%3Apr+is%3Aclosed...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Screenpipe — Archive
[IP_ADDRESS]
Pull requests · Screenpipe — Archive
[IP_ADDRESS]
Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Close tab
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
Close tab
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to content
Skip to content
Navigation Menu
Navigation Menu
Homepage
Platform
Solutions
Resources
Open Source
Enterprise
Pricing
Pricing
Search or jump to…
Search or jump to...
Sign in
Sign in
Sign up
Sign up
Appearance settings
screenpipe
screenpipe
/
screenpipe
screenpipe
Public
You must be signed in to change notification settings
Notifications
Fork 1.7k
Fork
1.7k
You must be signed in to star a repository
Star
18.6k
Code
Code
Issues 16
Issues
16
Pull requests 17
Pull requests
17
Discussions
Discussions
Actions
Actions
Projects
Projects
Security and quality
Security and quality
Insights
Insights
Pull requests: screenpipe/screenpipe
Pull requests: screenpipe/screenpipe
is:pr is:closed
Labels 43
Labels
43
Milestones 0
Milestones
0
New pull request
New pull request
Clear current search query, filters, and sorts
Clear current search query, filters, and sorts
17 Open
17 Open
1,593 Closed
1,593 Closed
Author
Author
Label
Label
Projects
Projects
Milestones
Milestones
Reviews
Reviews
Assignee
Assignee
Sort
Sort
Pull requests list
Pull requests list
docs(testing): add 3 recent regression test entries
docs(testing): add 3 recent regression test entries
#3224 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
testing: update spec from recent changes (2026-05-04)
testing: update spec from recent changes (2026-05-04)
#3223 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add circuit breaker for corrupted segmentation model
fix: add circuit breaker for corrupted segmentation model
#3222 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add a11y multi-line bbox regression entry
docs(testing): add a11y multi-line bbox regression entry
#3221 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add diagnostic logging for audio device configuration selection
fix: add diagnostic logging for audio device configuration selection
#3220 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs: improve SEO titles across generic pages
docs: improve SEO titles across generic pages
#3219 by
mintlify
mintlify
Bot
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3218 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add multi-line text bbox capture regression test
docs(testing): add multi-line text bbox capture regression test
#3217 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Windows GetWindowRect bounds regression test
docs(testing): add Windows GetWindowRect bounds regression test
#3216 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
Fix devcontainer cargo path
Fix devcontainer cargo path
#3214 by
julpel8
julpel8
Contributor
was merged
4 days ago
•
Review required before merging
Review required
fix(settings): api key regenerate cancel, apply button, manual edit
fix(settings): api key regenerate cancel, apply button, manual edit
#3212 by
Anshgrover23
Anshgrover23
Contributor
was merged
5 days ago
•
Review required before merging
Review required
docs(testing): add VACUUM INTO snapshot regression entry
docs(testing): add VACUUM INTO snapshot regression entry
#3211 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix(chat): allow input chip to be removed
fix(chat): allow input chip to be removed
#3210 by
thisisharsh7
thisisharsh7
Contributor
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
fix: graceful fallback when segmentation model cache is invalidated
fix: graceful fallback when segmentation model cache is invalidated
#3209 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
testing: update spec from recent changes (2026-05-03)
testing: update spec from recent changes (2026-05-03)
#3208 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add empty-state navigation button regression test
docs(testing): add empty-state navigation button regression test
#3207 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: audio dedup-skip metric — prevent false health check stalls
fix: audio dedup-skip metric — prevent false health check stalls
#3206 by
louis030195
louis030195
Collaborator
was closed
2 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3204 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add per-line search highlight regression test
docs(testing): add per-line search highlight regression test
#3203 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Apple Vision per-word OCR fast path regression test
docs(testing): add Apple Vision per-word OCR fast path regression test
#3202 by
louis030195
louis030195
Collaborator
was merged
last week
•
Review required before merging
Review required
docs(testing): add Windows AVX2 CPU support regression entry
docs(testing): add Windows AVX2 CPU support regression entry
#3201 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
docs(testing): add timeline Escape key regression test for Windows
docs(testing): add timeline Escape key regression test for Windows
#3200 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
fix: preserve original db error in write queue instead of masking with PoolTimedOut
fix: preserve original db error in write queue instead of masking with PoolTimedOut
#3199 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
testing: update spec from recent changes (2026-05-02)
testing: update spec from recent changes (2026-05-02)
#3198 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
docs(testing): add Bluetooth audio device hijack recovery regression test
docs(testing): add Bluetooth audio device hijack recovery regression test
#3197 by
louis030195
louis030195
Collaborator
was merged
last week
•
Review required before merging
Review required
Previous page
Previous
Page 1
1
2
Page 3
3
Page 4
4
Page 5
5
…
Page 63
63
Page 64
64
Next page
Next
ProTip!
Adding
no:label
no:label
will show everything without a label.
Footer
Footer
GitHub Homepage
© 2026 GitHub, Inc.
Footer navigation
Footer navigation
Terms
Terms
Privacy
Privacy
Security
Security
Status
Status
Community
Community
Docs
Docs
Contact
Contact
Manage cookies
Do not share my personal information...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.37865692,"top":0.15722266,"width":0.03956117,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"192.168.0.242","depth":4,"bounds":{"left":0.37865692,"top":0.16799681,"width":0.02443484,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.36236703,"top":0.05905826,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"bounds":{"left":0.26097074,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"bounds":{"left":0.27426863,"top":0.09577015,"width":0.03025266,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"bounds":{"left":0.26097074,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"bounds":{"left":0.27426863,"top":0.12849163,"width":0.05069814,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.26097074,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.27426863,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.36236703,"top":0.15722266,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.26097074,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.27426863,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.26097074,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.27426863,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.26097074,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.27426863,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"bounds":{"left":0.26097074,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"bounds":{"left":0.27426863,"top":0.32482043,"width":0.105884306,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.26379654,"top":0.34796488,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.26379654,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.27476728,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.28590426,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.29704124,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.3081782,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to content","depth":6,"bounds":{"left":0.37466756,"top":0.0518755,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"bounds":{"left":0.37466756,"top":0.05347167,"width":0.0029920214,"height":0.21468475},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Navigation Menu","depth":7,"bounds":{"left":0.37466756,"top":0.06464485,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Navigation Menu","depth":8,"bounds":{"left":0.37466756,"top":0.06743815,"width":0.038896278,"height":0.0518755},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Homepage","depth":7,"bounds":{"left":0.38530585,"top":0.06703911,"width":0.010638298,"height":0.027533919},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Platform","depth":12,"bounds":{"left":0.4012633,"top":0.06464485,"width":0.032413565,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Solutions","depth":12,"bounds":{"left":0.43367687,"top":0.06464485,"width":0.034242023,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Resources","depth":12,"bounds":{"left":0.46791887,"top":0.06464485,"width":0.03723404,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Source","depth":12,"bounds":{"left":0.50515294,"top":0.06464485,"width":0.043550532,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Enterprise","depth":12,"bounds":{"left":0.54870343,"top":0.06464485,"width":0.03656915,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Pricing","depth":12,"bounds":{"left":0.5852726,"top":0.06464485,"width":0.021941489,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pricing","depth":14,"bounds":{"left":0.58793217,"top":0.07302474,"width":0.01662234,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"bounds":{"left":0.8133311,"top":0.06863528,"width":0.10571808,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search or jump to...","depth":11,"bounds":{"left":0.8239694,"top":0.07462091,"width":0.042054523,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sign in","depth":8,"bounds":{"left":0.923371,"top":0.06783719,"width":0.02244016,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sign in","depth":9,"bounds":{"left":0.92736036,"top":0.073822826,"width":0.014461436,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sign up","depth":7,"bounds":{"left":0.94980055,"top":0.06783719,"width":0.024933511,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sign up","depth":8,"bounds":{"left":0.95412236,"top":0.073822826,"width":0.016289894,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Appearance settings","depth":9,"bounds":{"left":0.9787234,"top":0.06783719,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"screenpipe","depth":9,"bounds":{"left":0.3932846,"top":0.1245012,"width":0.032247342,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe","depth":10,"bounds":{"left":0.3932846,"top":0.1245012,"width":0.032247342,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":9,"bounds":{"left":0.4268617,"top":0.1245012,"width":0.0018284575,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"screenpipe","depth":9,"bounds":{"left":0.43001994,"top":0.1245012,"width":0.033909574,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe","depth":10,"bounds":{"left":0.43001994,"top":0.1245012,"width":0.033909574,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":9,"bounds":{"left":0.46891624,"top":0.12809257,"width":0.011968086,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"You must be signed in to change notification settings","depth":11,"bounds":{"left":0.8615359,"top":0.12210695,"width":0.04105718,"height":0.022346368},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":12,"bounds":{"left":0.87383646,"top":0.1272945,"width":0.02443484,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fork 1.7k","depth":11,"bounds":{"left":0.90525264,"top":0.12210695,"width":0.0390625,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fork","depth":12,"bounds":{"left":0.9175532,"top":0.1272945,"width":0.009640957,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1.7k","depth":13,"bounds":{"left":0.93018615,"top":0.1272945,"width":0.007480053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"You must be signed in to star a repository","depth":11,"bounds":{"left":0.94697475,"top":0.12210695,"width":0.042386968,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Star","depth":12,"bounds":{"left":0.95927525,"top":0.1272945,"width":0.010139627,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18.6k","depth":13,"bounds":{"left":0.9724069,"top":0.1272945,"width":0.010305851,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":11,"bounds":{"left":0.38530585,"top":0.1660016,"width":0.025099734,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":13,"bounds":{"left":0.3961104,"top":0.17118914,"width":0.011469414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Issues 16","depth":11,"bounds":{"left":0.41306517,"top":0.1660016,"width":0.03956117,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":13,"bounds":{"left":0.4240359,"top":0.17118914,"width":0.013630319,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16","depth":13,"bounds":{"left":0.4429854,"top":0.17198724,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests 17","depth":11,"bounds":{"left":0.4552859,"top":0.1660016,"width":0.054022606,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":13,"bounds":{"left":0.4659242,"top":0.17118914,"width":0.02925532,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17","depth":13,"bounds":{"left":0.50016624,"top":0.17198724,"width":0.004155585,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Discussions","depth":11,"bounds":{"left":0.5119681,"top":0.1660016,"width":0.040226065,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Discussions","depth":13,"bounds":{"left":0.52327126,"top":0.17118914,"width":0.025598405,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":11,"bounds":{"left":0.55485374,"top":0.1660016,"width":0.03025266,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":13,"bounds":{"left":0.5659907,"top":0.17118914,"width":0.015957447,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Projects","depth":11,"bounds":{"left":0.58776593,"top":0.1660016,"width":0.03174867,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Projects","depth":13,"bounds":{"left":0.59890294,"top":0.17118914,"width":0.01761968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality","depth":11,"bounds":{"left":0.6221742,"top":0.1660016,"width":0.05817819,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":13,"bounds":{"left":0.63397604,"top":0.17118914,"width":0.04255319,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":11,"bounds":{"left":0.68301195,"top":0.1660016,"width":0.03125,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":13,"bounds":{"left":0.69431514,"top":0.17118914,"width":0.016788565,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull requests: screenpipe/screenpipe","depth":10,"bounds":{"left":0.48520613,"top":0.21628092,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull requests: screenpipe/screenpipe","depth":11,"bounds":{"left":0.48520613,"top":0.22027135,"width":0.05701463,"height":0.1452514},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"is:pr is:closed","depth":12,"bounds":{"left":0.48520613,"top":0.21628092,"width":0.25731382,"height":0.025538707},"on_screen":true,"value":"is:pr is:closed","help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Labels 43","depth":12,"bounds":{"left":0.7478391,"top":0.21628092,"width":0.04338431,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Labels","depth":13,"bounds":{"left":0.75880986,"top":0.22226655,"width":0.016954787,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"43","depth":14,"bounds":{"left":0.7780917,"top":0.22386272,"width":0.0051529254,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Milestones 0","depth":12,"bounds":{"left":0.79089093,"top":0.21628092,"width":0.050199468,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Milestones","depth":13,"bounds":{"left":0.8018617,"top":0.22226655,"width":0.02642952,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":14,"bounds":{"left":0.8306183,"top":0.22386272,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"New pull request","depth":10,"bounds":{"left":0.84375,"top":0.21628092,"width":0.045711435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New pull request","depth":13,"bounds":{"left":0.8480718,"top":0.22226655,"width":0.03706782,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Clear current search query, filters, and sorts","depth":11,"bounds":{"left":0.48520613,"top":0.25618514,"width":0.10804521,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Clear current search query, filters, and sorts","depth":12,"bounds":{"left":0.49251994,"top":0.25618514,"width":0.10073138,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"17 Open","depth":12,"bounds":{"left":0.49085772,"top":0.29768556,"width":0.025598405,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17 Open","depth":13,"bounds":{"left":0.49750665,"top":0.29928172,"width":0.018949468,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1,593 Closed","depth":12,"bounds":{"left":0.52111036,"top":0.29768556,"width":0.03706782,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1,593 Closed","depth":13,"bounds":{"left":0.5277593,"top":0.29928172,"width":0.030418882,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Author","depth":12,"bounds":{"left":0.67669547,"top":0.29768556,"width":0.018450798,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Author","depth":13,"bounds":{"left":0.67669547,"top":0.29928172,"width":0.015791224,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Label","depth":12,"bounds":{"left":0.70578456,"top":0.29768556,"width":0.015458777,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Label","depth":13,"bounds":{"left":0.70578456,"top":0.29928172,"width":0.012799202,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Projects","depth":13,"bounds":{"left":0.7318817,"top":0.29768556,"width":0.021609042,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Projects","depth":14,"bounds":{"left":0.7318817,"top":0.29928172,"width":0.018949468,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Milestones","depth":13,"bounds":{"left":0.76545876,"top":0.29768556,"width":0.027094414,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Milestones","depth":14,"bounds":{"left":0.76545876,"top":0.29928172,"width":0.02443484,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Reviews","depth":13,"bounds":{"left":0.80452126,"top":0.29768556,"width":0.02144282,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Reviews","depth":14,"bounds":{"left":0.80452126,"top":0.29928172,"width":0.018783245,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Assignee","depth":12,"bounds":{"left":0.8366024,"top":0.29768556,"width":0.023603724,"height":0.016759777},"on_screen":true,"help_text":"Assignees","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Assignee","depth":13,"bounds":{"left":0.8366024,"top":0.29928172,"width":0.020944148,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Sort","depth":12,"bounds":{"left":0.8708444,"top":0.29768556,"width":0.012965426,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Sort","depth":13,"bounds":{"left":0.8708444,"top":0.29928172,"width":0.008976064,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull requests list","depth":10,"bounds":{"left":0.48553857,"top":0.32801276,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull requests list","depth":11,"bounds":{"left":0.48553857,"top":0.33080608,"width":0.03174867,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add 3 recent regression test entries","depth":13,"bounds":{"left":0.49883643,"top":0.33758977,"width":0.12732713,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add 3 recent regression test entries","depth":14,"bounds":{"left":0.49883643,"top":0.33758977,"width":0.12732713,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3224 by","depth":14,"bounds":{"left":0.49883643,"top":0.35993615,"width":0.019115692,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51795214,"top":0.35993615,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51795214,"top":0.35993615,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54454786,"top":0.35993615,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5718085,"top":0.35993615,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59391624,"top":0.35993615,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6156915,"top":0.35913807,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6186835,"top":0.35913807,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6186835,"top":0.35913807,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.3367917,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.33838788,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"testing: update spec from recent changes (2026-05-04)","depth":13,"bounds":{"left":0.49883643,"top":0.38946527,"width":0.14328457,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"testing: update spec from recent changes (2026-05-04)","depth":14,"bounds":{"left":0.49883643,"top":0.38946527,"width":0.14328457,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3223 by","depth":14,"bounds":{"left":0.49883643,"top":0.41181165,"width":0.019115692,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51795214,"top":0.41181165,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51795214,"top":0.41181165,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54454786,"top":0.41181165,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5718085,"top":0.41181165,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59391624,"top":0.41181165,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6156915,"top":0.41101357,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6186835,"top":0.41101357,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6186835,"top":0.41101357,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.38906625,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.3906624,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: add circuit breaker for corrupted segmentation model","depth":13,"bounds":{"left":0.49883643,"top":0.44173983,"width":0.14494681,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: add circuit breaker for corrupted segmentation model","depth":14,"bounds":{"left":0.49883643,"top":0.44173983,"width":0.14494681,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3222 by","depth":14,"bounds":{"left":0.49883643,"top":0.4640862,"width":0.019115692,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51795214,"top":0.4640862,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51795214,"top":0.4640862,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54454786,"top":0.4640862,"width":0.023769947,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5718085,"top":0.4640862,"width":0.021941489,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59375,"top":0.4640862,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.61552525,"top":0.4632881,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6185173,"top":0.4632881,"width":0.03025266,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6185173,"top":0.4632881,"width":0.03025266,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"bounds":{"left":0.8746675,"top":0.44094175,"width":0.009142287,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"bounds":{"left":0.8813165,"top":0.4425379,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add a11y multi-line bbox regression entry","depth":13,"bounds":{"left":0.49883643,"top":0.49401435,"width":0.14112367,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add a11y multi-line bbox regression entry","depth":14,"bounds":{"left":0.49883643,"top":0.49401435,"width":0.14112367,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3221 by","depth":14,"bounds":{"left":0.49883643,"top":0.51636076,"width":0.018450798,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51728725,"top":0.51636076,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51728725,"top":0.51636076,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54388297,"top":0.51636076,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5711436,"top":0.51636076,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59325135,"top":0.51636076,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6150266,"top":0.51556265,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6180186,"top":0.51556265,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6180186,"top":0.51556265,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.49321628,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.49481246,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: add diagnostic logging for audio device configuration selection","depth":13,"bounds":{"left":0.49883643,"top":0.54588985,"width":0.16805187,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: add diagnostic logging for audio device configuration selection","depth":14,"bounds":{"left":0.49883643,"top":0.54588985,"width":0.16805187,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3220 by","depth":14,"bounds":{"left":0.49883643,"top":0.56823623,"width":0.019115692,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51795214,"top":0.56823623,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51795214,"top":0.56823623,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54454786,"top":0.56823623,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5718085,"top":0.56823623,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59391624,"top":0.56823623,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6156915,"top":0.5674381,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6186835,"top":0.5674381,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6186835,"top":0.5674381,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.5454908,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.547087,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs: improve SEO titles across generic pages","depth":13,"bounds":{"left":0.49883643,"top":0.5981644,"width":0.116855055,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs: improve SEO titles across generic pages","depth":14,"bounds":{"left":0.49883643,"top":0.5981644,"width":0.116855055,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3219 by","depth":14,"bounds":{"left":0.49883643,"top":0.62051076,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"bounds":{"left":0.51745343,"top":0.62051076,"width":0.013796543,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"bounds":{"left":0.51745343,"top":0.62051076,"width":0.013796543,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"bounds":{"left":0.5347407,"top":0.62051076,"width":0.0066489363,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.5437167,"top":0.62051076,"width":0.024933511,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"bounds":{"left":0.56865025,"top":0.62051076,"width":0.020611702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.5905917,"top":0.6197127,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.59358376,"top":0.6197127,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.59358376,"top":0.6197127,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.59736633,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.5989625,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"changelog: week of may 3, 2026","depth":13,"bounds":{"left":0.49883643,"top":0.6500399,"width":0.08228058,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"changelog: week of may 3, 2026","depth":14,"bounds":{"left":0.49883643,"top":0.6500399,"width":0.08228058,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3218 by","depth":14,"bounds":{"left":0.49883643,"top":0.6723863,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"bounds":{"left":0.51745343,"top":0.6723863,"width":0.013796543,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"bounds":{"left":0.51745343,"top":0.6723863,"width":0.013796543,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"bounds":{"left":0.5347407,"top":0.6723863,"width":0.0066489363,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5437167,"top":0.6723863,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.5668218,"top":0.6723863,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.58859706,"top":0.6715882,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.5915891,"top":0.6715882,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.5915891,"top":0.6715882,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"bounds":{"left":0.8746675,"top":0.64964086,"width":0.009142287,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"bounds":{"left":0.8813165,"top":0.651237,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add multi-line text bbox capture regression test","depth":13,"bounds":{"left":0.49883643,"top":0.70231444,"width":0.15741356,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add multi-line text bbox capture regression test","depth":14,"bounds":{"left":0.49883643,"top":0.70231444,"width":0.15741356,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3217 by","depth":14,"bounds":{"left":0.49883643,"top":0.7246608,"width":0.018284574,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.517121,"top":0.7246608,"width":0.023271276,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.517121,"top":0.7246608,"width":0.023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5437167,"top":0.7246608,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5711436,"top":0.7246608,"width":0.021941489,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.5930851,"top":0.7246608,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.61486036,"top":0.7238627,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6178524,"top":0.7238627,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6178524,"top":0.7238627,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.7015164,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.70311254,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Windows GetWindowRect bounds regression test","depth":13,"bounds":{"left":0.49883643,"top":0.75458896,"width":0.17270611,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Windows GetWindowRect bounds regression test","depth":14,"bounds":{"left":0.49883643,"top":0.75458896,"width":0.17270611,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3216 by","depth":14,"bounds":{"left":0.49883643,"top":0.77693534,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51745343,"top":0.77693534,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51745343,"top":0.77693534,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5440492,"top":0.77693534,"width":0.023769947,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.57130986,"top":0.77693534,"width":0.021941489,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59325135,"top":0.77693534,"width":0.020611702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.61519283,"top":0.7761373,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.61818486,"top":0.7761373,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.61818486,"top":0.7761373,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.7537909,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.75538707,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fix devcontainer cargo path","depth":13,"bounds":{"left":0.49883643,"top":0.8064645,"width":0.0703125,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fix devcontainer cargo path","depth":14,"bounds":{"left":0.49883643,"top":0.8064645,"width":0.0703125,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3214 by","depth":14,"bounds":{"left":0.49883643,"top":0.8288109,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"julpel8","depth":14,"bounds":{"left":0.51745343,"top":0.8288109,"width":0.012632979,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by julpel8","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"julpel8","depth":15,"bounds":{"left":0.51745343,"top":0.8288109,"width":0.012632979,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Contributor","depth":16,"bounds":{"left":0.53357714,"top":0.8288109,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.55917555,"top":0.8288109,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"bounds":{"left":0.5831117,"top":0.8288109,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.60488695,"top":0.82801276,"width":0.0031582448,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6080452,"top":0.82801276,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6080452,"top":0.82801276,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix(settings): api key regenerate cancel, apply button, manual edit","depth":13,"bounds":{"left":0.49883643,"top":0.858739,"width":0.1662234,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(settings): api key regenerate cancel, apply button, manual edit","depth":14,"bounds":{"left":0.49883643,"top":0.858739,"width":0.1662234,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3212 by","depth":14,"bounds":{"left":0.49883643,"top":0.8810854,"width":0.018450798,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Anshgrover23","depth":14,"bounds":{"left":0.51728725,"top":0.8810854,"width":0.02642952,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by Anshgrover23","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Anshgrover23","depth":15,"bounds":{"left":0.51728725,"top":0.8810854,"width":0.02642952,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Contributor","depth":16,"bounds":{"left":0.5472075,"top":0.8810854,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.5728058,"top":0.8810854,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5 days ago","depth":15,"bounds":{"left":0.59674203,"top":0.8810854,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6185173,"top":0.8802873,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6215093,"top":0.8802873,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6215093,"top":0.8802873,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add VACUUM INTO snapshot regression entry","depth":13,"bounds":{"left":0.49883643,"top":0.91101354,"width":0.15275931,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add VACUUM INTO snapshot regression entry","depth":14,"bounds":{"left":0.49883643,"top":0.91101354,"width":0.15275931,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3211 by","depth":14,"bounds":{"left":0.49883643,"top":0.9333599,"width":0.017952127,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51678854,"top":0.9333599,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51678854,"top":0.9333599,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5433843,"top":0.9333599,"width":0.023769947,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.570645,"top":0.9333599,"width":0.021941489,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59258646,"top":0.9333599,"width":0.020611702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.61452794,"top":0.9325619,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.61752,"top":0.9325619,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.61752,"top":0.9325619,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.9102155,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.91181165,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix(chat): allow input chip to be removed","depth":13,"bounds":{"left":0.49883643,"top":0.9628891,"width":0.10172872,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(chat): allow input chip to be removed","depth":14,"bounds":{"left":0.49883643,"top":0.9628891,"width":0.10172872,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3210 by","depth":14,"bounds":{"left":0.49883643,"top":0.98523545,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"thisisharsh7","depth":14,"bounds":{"left":0.51745343,"top":0.98523545,"width":0.022606382,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by thisisharsh7","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"thisisharsh7","depth":15,"bounds":{"left":0.51745343,"top":0.98523545,"width":0.022606382,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Contributor","depth":16,"bounds":{"left":0.54355055,"top":0.98523545,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.56914896,"top":0.98523545,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"bounds":{"left":0.5930851,"top":0.98523545,"width":0.020611702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6150266,"top":0.98443735,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6180186,"top":0.98443735,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6180186,"top":0.98443735,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.96249,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.9640862,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: graceful fallback when segmentation model cache is invalidated","depth":13,"bounds":{"left":0.49883643,"top":1.0,"width":0.1705452,"height":-0.01516366},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: graceful fallback when segmentation model cache is invalidated","depth":14,"bounds":{"left":0.49883643,"top":1.0,"width":0.1705452,"height":-0.01516366},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3209 by","depth":14,"bounds":{"left":0.49883643,"top":1.0,"width":0.019281914,"height":-0.03750992},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.5181183,"top":1.0,"width":0.023105053,"height":-0.03750992},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.5181183,"top":1.0,"width":0.023105053,"height":-0.03750992},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5447141,"top":1.0,"width":0.023769947,"height":-0.03750992},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.57197475,"top":1.0,"width":0.021941489,"height":-0.03750992},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59391624,"top":1.0,"width":0.020611702,"height":-0.03750992},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6158577,"top":1.0,"width":0.0029920214,"height":-0.03671193},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.61884975,"top":1.0,"width":0.030086435,"height":-0.03671193},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.61884975,"top":1.0,"width":0.030086435,"height":-0.03671193},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"bounds":{"left":0.8746675,"top":1.0,"width":0.009142287,"height":-0.014365554},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"bounds":{"left":0.8813165,"top":1.0,"width":0.002493351,"height":-0.015961647},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"testing: update spec from recent changes (2026-05-03)","depth":13,"bounds":{"left":0.49883643,"top":1.0,"width":0.14311835,"height":-0.067438126},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"testing: update spec from recent changes (2026-05-03)","depth":14,"bounds":{"left":0.49883643,"top":1.0,"width":0.14311835,"height":-0.067438126},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3208 by","depth":14,"bounds":{"left":0.49883643,"top":1.0,"width":0.019281914,"height":-0.0897845},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.5181183,"top":1.0,"width":0.023105053,"height":-0.0897845},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.5181183,"top":1.0,"width":0.023105053,"height":-0.0897845},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5447141,"top":1.0,"width":0.023936171,"height":-0.0897845},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.57197475,"top":1.0,"width":0.022107713,"height":-0.0897845},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.5940825,"top":1.0,"width":0.02044548,"height":-0.0897845},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6158577,"top":1.0,"width":0.0029920214,"height":-0.0889864},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.61884975,"top":1.0,"width":0.030086435,"height":-0.0889864},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.61884975,"top":1.0,"width":0.030086435,"height":-0.0889864},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":1.0,"width":0.008643617,"height":-0.06664002},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":1.0,"width":0.0019946808,"height":-0.06823623},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add empty-state navigation button regression test","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add empty-state navigation button regression test","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3207 by","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: audio dedup-skip metric — prevent false health check stalls","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: audio dedup-skip metric — prevent false health check stalls","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3206 by","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2 days ago","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"changelog: week of may 3, 2026","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"changelog: week of may 3, 2026","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3204 by","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"on_screen":false,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add per-line search highlight regression test","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add per-line search highlight regression test","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3203 by","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Apple Vision per-word OCR fast path regression test","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Apple Vision per-word OCR fast path regression test","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3202 by","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Windows AVX2 CPU support regression entry","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Windows AVX2 CPU support regression entry","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3201 by","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add timeline Escape key regression test for Windows","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add timeline Escape key regression test for Windows","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3200 by","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: preserve original db error in write queue instead of masking with PoolTimedOut","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: preserve original db error in write queue instead of masking with PoolTimedOut","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3199 by","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"testing: update spec from recent changes (2026-05-02)","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"testing: update spec from recent changes (2026-05-02)","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3198 by","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Bluetooth audio device hijack recovery regression test","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Bluetooth audio device hijack recovery regression test","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3197 by","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"last week","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Previous page","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Previous","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 1","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 3","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 4","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 5","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"…","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 63","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"63","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Page 64","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"64","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Next page","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Next","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ProTip!","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Adding","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"no:label","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"no:label","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"will show everything without a label.","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Footer","depth":7,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Footer","depth":8,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub Homepage","depth":7,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"© 2026 GitHub, Inc.","depth":8,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Footer navigation","depth":8,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Footer navigation","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Terms","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Terms","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Privacy","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Privacy","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Status","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Status","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Community","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Community","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Docs","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Docs","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Contact","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Contact","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Manage cookies","depth":11,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Do not share my personal information","depth":11,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-3634706398058112898
|
-4772745185547706724
|
visual_change
|
accessibility
|
NULL
|
Screenpipe — Archive
[IP_ADDRESS]
Pull requests · Screenpipe — Archive
[IP_ADDRESS]
Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Close tab
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
Close tab
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to content
Skip to content
Navigation Menu
Navigation Menu
Homepage
Platform
Solutions
Resources
Open Source
Enterprise
Pricing
Pricing
Search or jump to…
Search or jump to...
Sign in
Sign in
Sign up
Sign up
Appearance settings
screenpipe
screenpipe
/
screenpipe
screenpipe
Public
You must be signed in to change notification settings
Notifications
Fork 1.7k
Fork
1.7k
You must be signed in to star a repository
Star
18.6k
Code
Code
Issues 16
Issues
16
Pull requests 17
Pull requests
17
Discussions
Discussions
Actions
Actions
Projects
Projects
Security and quality
Security and quality
Insights
Insights
Pull requests: screenpipe/screenpipe
Pull requests: screenpipe/screenpipe
is:pr is:closed
Labels 43
Labels
43
Milestones 0
Milestones
0
New pull request
New pull request
Clear current search query, filters, and sorts
Clear current search query, filters, and sorts
17 Open
17 Open
1,593 Closed
1,593 Closed
Author
Author
Label
Label
Projects
Projects
Milestones
Milestones
Reviews
Reviews
Assignee
Assignee
Sort
Sort
Pull requests list
Pull requests list
docs(testing): add 3 recent regression test entries
docs(testing): add 3 recent regression test entries
#3224 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
testing: update spec from recent changes (2026-05-04)
testing: update spec from recent changes (2026-05-04)
#3223 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add circuit breaker for corrupted segmentation model
fix: add circuit breaker for corrupted segmentation model
#3222 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add a11y multi-line bbox regression entry
docs(testing): add a11y multi-line bbox regression entry
#3221 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add diagnostic logging for audio device configuration selection
fix: add diagnostic logging for audio device configuration selection
#3220 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs: improve SEO titles across generic pages
docs: improve SEO titles across generic pages
#3219 by
mintlify
mintlify
Bot
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3218 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add multi-line text bbox capture regression test
docs(testing): add multi-line text bbox capture regression test
#3217 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Windows GetWindowRect bounds regression test
docs(testing): add Windows GetWindowRect bounds regression test
#3216 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
Fix devcontainer cargo path
Fix devcontainer cargo path
#3214 by
julpel8
julpel8
Contributor
was merged
4 days ago
•
Review required before merging
Review required
fix(settings): api key regenerate cancel, apply button, manual edit
fix(settings): api key regenerate cancel, apply button, manual edit
#3212 by
Anshgrover23
Anshgrover23
Contributor
was merged
5 days ago
•
Review required before merging
Review required
docs(testing): add VACUUM INTO snapshot regression entry
docs(testing): add VACUUM INTO snapshot regression entry
#3211 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix(chat): allow input chip to be removed
fix(chat): allow input chip to be removed
#3210 by
thisisharsh7
thisisharsh7
Contributor
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
fix: graceful fallback when segmentation model cache is invalidated
fix: graceful fallback when segmentation model cache is invalidated
#3209 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
testing: update spec from recent changes (2026-05-03)
testing: update spec from recent changes (2026-05-03)
#3208 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add empty-state navigation button regression test
docs(testing): add empty-state navigation button regression test
#3207 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: audio dedup-skip metric — prevent false health check stalls
fix: audio dedup-skip metric — prevent false health check stalls
#3206 by
louis030195
louis030195
Collaborator
was closed
2 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3204 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add per-line search highlight regression test
docs(testing): add per-line search highlight regression test
#3203 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Apple Vision per-word OCR fast path regression test
docs(testing): add Apple Vision per-word OCR fast path regression test
#3202 by
louis030195
louis030195
Collaborator
was merged
last week
•
Review required before merging
Review required
docs(testing): add Windows AVX2 CPU support regression entry
docs(testing): add Windows AVX2 CPU support regression entry
#3201 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
docs(testing): add timeline Escape key regression test for Windows
docs(testing): add timeline Escape key regression test for Windows
#3200 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
fix: preserve original db error in write queue instead of masking with PoolTimedOut
fix: preserve original db error in write queue instead of masking with PoolTimedOut
#3199 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
testing: update spec from recent changes (2026-05-02)
testing: update spec from recent changes (2026-05-02)
#3198 by
louis030195
louis030195
Collaborator
was closed
last week
•
Review required before merging
Review required
docs(testing): add Bluetooth audio device hijack recovery regression test
docs(testing): add Bluetooth audio device hijack recovery regression test
#3197 by
louis030195
louis030195
Collaborator
was merged
last week
•
Review required before merging
Review required
Previous page
Previous
Page 1
1
2
Page 3
3
Page 4
4
Page 5
5
…
Page 63
63
Page 64
64
Next page
Next
ProTip!
Adding
no:label
no:label
will show everything without a label.
Footer
Footer
GitHub Homepage
© 2026 GitHub, Inc.
Footer navigation
Footer navigation
Terms
Terms
Privacy
Privacy
Security
Security
Status
Status
Community
Community
Docs
Docs
Contact
Contact
Manage cookies
Do not share my personal information...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10190
|
467
|
3
|
2026-05-08T17:10:29.902609+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260229902_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionFileEditViewHistoryWindowHelp‹ >0 lhAPP ( NotionFileEditViewHistoryWindowHelp‹ >0 lhAPP (-zsh)DOCKERDEV (docker)882JY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY] (-zsh)-zsh• 84screenpipe*•₴5100% C8 Fri 8 May 20:10:29181-zsh₴6APPN3$IFirefoxJY-<019/-1mport-opportunity-batch-jobJY-20293-enable-status-field-for-pipedrive-dealsJY-20191-remove-commands-interactive-promptsJY-20118-change-default-sync-strategyJY-20183-add-cache-on-auto-log-delayJY-20197-add-import-opportunity-batch-job20118-hs-opportunity-make-webhook-strategy-defaultJY-20118-make-default-hs-opportunity-sync-strategy-webhook-basedJY-20196-handle-opportunity-without-noteJY-20118-improve-opportunity-importJY-20189-handle-activity-search-on-deleted-groupsJY-20160JY-20145-filter-out-converted-leads-when-matchingJY-20150-skip-push-summary-on-summary-ready-if-autologJY-20132-fix-note-encodingJY-19792-clean-LogsJY-20117-fix-sync-profile-fields-on-empty-fieldslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20725-handle-HS-search-rate-limitSwitched to a new branch 'JY-20725-handle-HS-search-rate-limit'lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ D...
|
NULL
|
737425236215912886
|
NULL
|
visual_change
|
ocr
|
NULL
|
NotionFileEditViewHistoryWindowHelp‹ >0 lhAPP ( NotionFileEditViewHistoryWindowHelp‹ >0 lhAPP (-zsh)DOCKERDEV (docker)882JY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY] (-zsh)-zsh• 84screenpipe*•₴5100% C8 Fri 8 May 20:10:29181-zsh₴6APPN3$IFirefoxJY-<019/-1mport-opportunity-batch-jobJY-20293-enable-status-field-for-pipedrive-dealsJY-20191-remove-commands-interactive-promptsJY-20118-change-default-sync-strategyJY-20183-add-cache-on-auto-log-delayJY-20197-add-import-opportunity-batch-job20118-hs-opportunity-make-webhook-strategy-defaultJY-20118-make-default-hs-opportunity-sync-strategy-webhook-basedJY-20196-handle-opportunity-without-noteJY-20118-improve-opportunity-importJY-20189-handle-activity-search-on-deleted-groupsJY-20160JY-20145-filter-out-converted-leads-when-matchingJY-20150-skip-push-summary-on-summary-ready-if-autologJY-20132-fix-note-encodingJY-19792-clean-LogsJY-20117-fix-sync-profile-fields-on-empty-fieldslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20725-handle-HS-search-rate-limitSwitched to a new branch 'JY-20725-handle-HS-search-rate-limit'lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ D...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10189
|
467
|
2
|
2026-05-08T17:10:03.998285+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260203998_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCK NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCKERDEV (docker)982JY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPAPP (-zsh)-zshJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20725-handle-HS-search-rate-limitSwitched to a new branch 'JY-20725-handle-HS-search-rate-limit'Lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ I‹ >0 lobl100% C8Fri 8 May 20:10:04• 84screenpipe*•$5-zsh₴6APP...
|
NULL
|
2603221119567920662
|
NULL
|
idle
|
ocr
|
NULL
|
NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCK NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCKERDEV (docker)982JY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPAPP (-zsh)-zshJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20725-handle-HS-search-rate-limitSwitched to a new branch 'JY-20725-handle-HS-search-rate-limit'Lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ I‹ >0 lobl100% C8Fri 8 May 20:10:04• 84screenpipe*•$5-zsh₴6APP...
|
10187
|
NULL
|
NULL
|
NULL
|
|
10188
|
468
|
2
|
2026-05-08T17:10:03.790019+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260203790_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionFileEdiVIeWMistonWindowheltCode diff reviewo NotionFileEdiVIeWMistonWindowheltCode diff reviewopen separate tickets for them rather than expand thswitch cursor() to lazyByid(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dur dre-care uis rr ana ve lone in sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccoctod throo Iaraval itaration mothode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY id-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r elDB connection: held open and busy for the entire iteWrite a message…Pull requests • screenpipe/screenpipe • GitHubHome I Hostinger@ Login - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tab• github.com/screenpipe/screenpipe/pulls?page=2&¢PatformvSolutionsPesources# screenoioe /screenbioe (Publio‹> Code• Issues 16Pull requests• isX Cl881881L Lukas Kovalik's No..100% 12rho May 20.10:04Edited 2h ago*...n Homea Testb DailyAgents+ New agentWorkspace* Quick Note- Work• Jira ticketView of Sprint17 DailyPlan7 SprintStefka 1-11 Todoã devEvaluationKnowledaem IdeasE Home viewsA Integration-appWork Knowledaetesting keyboard4 Todo5 YEAR 2026[ New page(9 New pagePersonal Home1 LOGSBudaet2 ApartmánRouterª) Population decline explained1 Seniority LevelsПП Martila Interview Preparation(9 Pain Trackel7 New chat x0Work Knowledgee Hubspot / Hubspot APl callsnulvio vynunivinvourtuiConUuUrtMINMethodVia executeRequest/?Rate Limitclient->getOwnersArchived) →makekequestexecute()ANO4 RUPSTapp/services Activity Hubspot/service.phpunis service uses >thisoercrmService->searchCallsForPeriod).(the CRM Service.php) - it makes no direct HubSpot API calls itself. All calls delegate through crmService->getCall()Critical Findings1. Line 1313 — raw searchApi()->doSearch() - matchExactlyByParticipant() in Service.php:$response = sthis->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completelv around the Cllent wrapper — no 429 handlina, no RateLim1tException, no rate limit awareness• Uses the search rate limit bucket• Can be replaced with Sthis->client->search(contacts, Spayload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():$hsAccounts = Sthis->client->qetInstance()->companies()->searchByDomain(ScompanyName, $companyProperties):• Usesvi SDK's searchByDomain which calls a search endooint — hits the search rate limit bucket• No 420 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or "" for commands...
|
NULL
|
-3076176584023677374
|
NULL
|
idle
|
ocr
|
NULL
|
NotionFileEdiVIeWMistonWindowheltCode diff reviewo NotionFileEdiVIeWMistonWindowheltCode diff reviewopen separate tickets for them rather than expand thswitch cursor() to lazyByid(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dur dre-care uis rr ana ve lone in sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccoctod throo Iaraval itaration mothode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY id-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r elDB connection: held open and busy for the entire iteWrite a message…Pull requests • screenpipe/screenpipe • GitHubHome I Hostinger@ Login - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tab• github.com/screenpipe/screenpipe/pulls?page=2&¢PatformvSolutionsPesources# screenoioe /screenbioe (Publio‹> Code• Issues 16Pull requests• isX Cl881881L Lukas Kovalik's No..100% 12rho May 20.10:04Edited 2h ago*...n Homea Testb DailyAgents+ New agentWorkspace* Quick Note- Work• Jira ticketView of Sprint17 DailyPlan7 SprintStefka 1-11 Todoã devEvaluationKnowledaem IdeasE Home viewsA Integration-appWork Knowledaetesting keyboard4 Todo5 YEAR 2026[ New page(9 New pagePersonal Home1 LOGSBudaet2 ApartmánRouterª) Population decline explained1 Seniority LevelsПП Martila Interview Preparation(9 Pain Trackel7 New chat x0Work Knowledgee Hubspot / Hubspot APl callsnulvio vynunivinvourtuiConUuUrtMINMethodVia executeRequest/?Rate Limitclient->getOwnersArchived) →makekequestexecute()ANO4 RUPSTapp/services Activity Hubspot/service.phpunis service uses >thisoercrmService->searchCallsForPeriod).(the CRM Service.php) - it makes no direct HubSpot API calls itself. All calls delegate through crmService->getCall()Critical Findings1. Line 1313 — raw searchApi()->doSearch() - matchExactlyByParticipant() in Service.php:$response = sthis->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completelv around the Cllent wrapper — no 429 handlina, no RateLim1tException, no rate limit awareness• Uses the search rate limit bucket• Can be replaced with Sthis->client->search(contacts, Spayload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():$hsAccounts = Sthis->client->qetInstance()->companies()->searchByDomain(ScompanyName, $companyProperties):• Usesvi SDK's searchByDomain which calls a search endooint — hits the search rate limit bucket• No 420 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or "" for commands...
|
10186
|
NULL
|
NULL
|
NULL
|
|
10187
|
467
|
1
|
2026-05-08T17:09:33.060189+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260173060_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCK NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCKERDEV (docker)982JY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPAPP (-zsh)-zshJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20725-handle-HS-search-rate-limitSwitched to a new branch 'JY-20725-handle-HS-search-rate-limit'Lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ I‹ >0 lobl100% C8• 84screenpipe*•$5-zshFri 8 May 20:09:33T81₴6APP...
|
NULL
|
8713527972267603826
|
NULL
|
idle
|
ocr
|
NULL
|
NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCK NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCKERDEV (docker)982JY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPAPP (-zsh)-zshJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20725-handle-HS-search-rate-limitSwitched to a new branch 'JY-20725-handle-HS-search-rate-limit'Lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ I‹ >0 lobl100% C8• 84screenpipe*•$5-zshFri 8 May 20:09:33T81₴6APP...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10186
|
468
|
1
|
2026-05-08T17:09:32.800286+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260172800_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionFileEdiVIeWMistonWindowheltCode diff reviewo NotionFileEdiVIeWMistonWindowheltCode diff reviewopen separate tickets for them rather than expand thswitch cursor() to lazyByid(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dur dre-care uis rr ana ve lone in sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccoctod throo Iaraval itaration mothode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY id-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r elDB connection: held open and busy for the entire iteWrite a message…Pull requests • screenpipe/screenpipe • GitHubHome I Hostinger@ Login - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tab• github.com/screenpipe/screenpipe/pulls?page=2&¢PatformvSolutionsPesources# screenoioe /screenbioe (Publio‹> Code• Issues 16Pull requests• isX Cl881881L Lukas Kovalik's No..100% 12rho May 20:09.33Edited 2h ago*...n Homea Testb DailyAgents+ New agentWorkspace* Quick Note- Work• Jira ticketView of Sprint17 DailyPlan7 SprintStefka 1-11 Todoã devEvaluationKnowledaem IdeasE Home viewsA Integration-appWork Knowledaetesting keyboard4 Todo5 YEAR 2026[ New page(9 New pagePersonal Home1 LOGSBudaet2 ApartmánRouterª) Population decline explained1 Seniority LevelsПП Martila Interview Preparation(9 Pain Trackel7 New chat x0Work Knowledgee Hubspot / Hubspot APl callsnulvio vynunivinvourtuiConUuUrtMINMethodVia executeRequest/?Rate Limitclient->getOwnersArchived) →makekequestexecute()ANO4 RUPSTapp/services Activity Hubspot/service.phpunis service uses >thisoercrmService->searchCallsForPeriod).(the CRM Service.php) - it makes no direct HubSpot API calls itself. All calls delegate through crmService->getCall()Critical Findings1. Line 1313 — raw searchApi()->doSearch() - matchExactlyByParticipant() in Service.php:$response = sthis->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completelv around the Cllent wrapper — no 429 handlina, no RateLim1tException, no rate limit awareness• Uses the search rate limit bucket• Can be replaced with Sthis->client->search(contacts, Spayload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():$hsAccounts = Sthis->client->qetInstance()->companies()->searchByDomain(ScompanyName, $companyProperties):• Usesvi SDK's searchByDomain which calls a search endooint — hits the search rate limit bucket• No 420 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or "" for commands...
|
NULL
|
-7872287853153970405
|
NULL
|
idle
|
ocr
|
NULL
|
NotionFileEdiVIeWMistonWindowheltCode diff reviewo NotionFileEdiVIeWMistonWindowheltCode diff reviewopen separate tickets for them rather than expand thswitch cursor() to lazyByid(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dur dre-care uis rr ana ve lone in sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccoctod throo Iaraval itaration mothode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY id-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r elDB connection: held open and busy for the entire iteWrite a message…Pull requests • screenpipe/screenpipe • GitHubHome I Hostinger@ Login - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tab• github.com/screenpipe/screenpipe/pulls?page=2&¢PatformvSolutionsPesources# screenoioe /screenbioe (Publio‹> Code• Issues 16Pull requests• isX Cl881881L Lukas Kovalik's No..100% 12rho May 20:09.33Edited 2h ago*...n Homea Testb DailyAgents+ New agentWorkspace* Quick Note- Work• Jira ticketView of Sprint17 DailyPlan7 SprintStefka 1-11 Todoã devEvaluationKnowledaem IdeasE Home viewsA Integration-appWork Knowledaetesting keyboard4 Todo5 YEAR 2026[ New page(9 New pagePersonal Home1 LOGSBudaet2 ApartmánRouterª) Population decline explained1 Seniority LevelsПП Martila Interview Preparation(9 Pain Trackel7 New chat x0Work Knowledgee Hubspot / Hubspot APl callsnulvio vynunivinvourtuiConUuUrtMINMethodVia executeRequest/?Rate Limitclient->getOwnersArchived) →makekequestexecute()ANO4 RUPSTapp/services Activity Hubspot/service.phpunis service uses >thisoercrmService->searchCallsForPeriod).(the CRM Service.php) - it makes no direct HubSpot API calls itself. All calls delegate through crmService->getCall()Critical Findings1. Line 1313 — raw searchApi()->doSearch() - matchExactlyByParticipant() in Service.php:$response = sthis->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completelv around the Cllent wrapper — no 429 handlina, no RateLim1tException, no rate limit awareness• Uses the search rate limit bucket• Can be replaced with Sthis->client->search(contacts, Spayload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():$hsAccounts = Sthis->client->qetInstance()->companies()->searchByDomain(ScompanyName, $companyProperties):• Usesvi SDK's searchByDomain which calls a search endooint — hits the search rate limit bucket• No 420 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or "" for commands...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10185
|
467
|
0
|
2026-05-08T17:09:02.182912+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260142182_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCK NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCKER₴1DEV (docker)982JY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPAPP (-zsh)-zshJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20725-handle-HS-search-rate-limitSwitched to a new branch 'JY-20725-handle-HS-search-rate-limit'Lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ I‹ >0 lobl100% C8Fri 8 May 20:09:02• 84screenpipe*•$5-zsh₴6APP...
|
NULL
|
-5372134749427196852
|
NULL
|
idle
|
ocr
|
NULL
|
NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCK NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCKER₴1DEV (docker)982JY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPAPP (-zsh)-zshJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20725-handle-HS-search-rate-limitSwitched to a new branch 'JY-20725-handle-HS-search-rate-limit'Lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ I‹ >0 lobl100% C8Fri 8 May 20:09:02• 84screenpipe*•$5-zsh₴6APP...
|
10183
|
NULL
|
NULL
|
NULL
|
|
10184
|
468
|
0
|
2026-05-08T17:09:01.794536+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260141794_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionFileEdiVIeWMistonWindowheltCode diff reviewo NotionFileEdiVIeWMistonWindowheltCode diff reviewopen separate tickets for them rather than expand thswitch cursor() to lazyByid(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dur dre-care uis rr ana ve lone in sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccoctod throo Iaraval itaration mothode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY ic-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r elDB connection: held open and busy for the entire iteWrite a message…Pull requests • screenpipe/screenpipe • GitHubHome I HostingerLogin - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tab• github.com/screenpipe/screenpipe/pulls?page=2&¢PatformvSolutionsPesources# screenoioe /screenbioe (Publio‹> Code• Issues 16Pull requests• isX Cl881881L Lukas Kovalik's No..100% 12Fri 8 May 20:09:01Edited 2h ago*...n Homea Testb DailyAgents+ New agentWorkspace* Quick Note- Work• Jira ticketView of Sprint17 DailyPlan7 SprintStefka 1-11 Todoã devEvaluationKnowledaem IdeasE Home viewsA Integration-appWork Knowledaetesting keyboard4 Todo5 YEAR 2026[ New page(9 New pagePersonal Home1 LOGSBudaet2 ApartmánRouterª) Population decline explained1 Seniority LevelsПП Martila Interview Preparation(9 Pain Trackel7 New chat x0Work Knowledgee Hubspot / Hubspot APl callsnulvio vynunivinvourtuiConUuUrtMINMethodVia executeRequest/?Rate Limitclient->getOwnersArchived) →makekequestexecute()ANO4 RUPSTapp/services Activity Hubspot/service.phpunis service uses >thisoercrmService->searchCallsForPeriod).(the CRM Service.php) - it makes no direct HubSpot API calls itself. All calls delegate through crmService->getCall()Critical Findings1. Line 1313 — raw searchApi()->doSearch() - matchExactlyByParticipant() in Service.php:$response = sthis->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completelv around the Cllent wrapper — no 429 handlina, no RateLim1tException, no rate limit awareness• Uses the search rate limit bucket• Can he renlaced with sthis-sclient-scearch(contacts snavload) — same endhoint same recult adds 420 nrotection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():$hsAccounts = Sthis->client->qetInstance()->companies()->searchByDomain(ScompanyName, $companyProperties):• Usesvi SDK's searchByDomain which calls a search endooint — hits the search rate limit bucket• No 420 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or "" for commands...
|
NULL
|
1909715807511939518
|
NULL
|
idle
|
ocr
|
NULL
|
NotionFileEdiVIeWMistonWindowheltCode diff reviewo NotionFileEdiVIeWMistonWindowheltCode diff reviewopen separate tickets for them rather than expand thswitch cursor() to lazyByid(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dur dre-care uis rr ana ve lone in sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccoctod throo Iaraval itaration mothode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY ic-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r elDB connection: held open and busy for the entire iteWrite a message…Pull requests • screenpipe/screenpipe • GitHubHome I HostingerLogin - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tab• github.com/screenpipe/screenpipe/pulls?page=2&¢PatformvSolutionsPesources# screenoioe /screenbioe (Publio‹> Code• Issues 16Pull requests• isX Cl881881L Lukas Kovalik's No..100% 12Fri 8 May 20:09:01Edited 2h ago*...n Homea Testb DailyAgents+ New agentWorkspace* Quick Note- Work• Jira ticketView of Sprint17 DailyPlan7 SprintStefka 1-11 Todoã devEvaluationKnowledaem IdeasE Home viewsA Integration-appWork Knowledaetesting keyboard4 Todo5 YEAR 2026[ New page(9 New pagePersonal Home1 LOGSBudaet2 ApartmánRouterª) Population decline explained1 Seniority LevelsПП Martila Interview Preparation(9 Pain Trackel7 New chat x0Work Knowledgee Hubspot / Hubspot APl callsnulvio vynunivinvourtuiConUuUrtMINMethodVia executeRequest/?Rate Limitclient->getOwnersArchived) →makekequestexecute()ANO4 RUPSTapp/services Activity Hubspot/service.phpunis service uses >thisoercrmService->searchCallsForPeriod).(the CRM Service.php) - it makes no direct HubSpot API calls itself. All calls delegate through crmService->getCall()Critical Findings1. Line 1313 — raw searchApi()->doSearch() - matchExactlyByParticipant() in Service.php:$response = sthis->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completelv around the Cllent wrapper — no 429 handlina, no RateLim1tException, no rate limit awareness• Uses the search rate limit bucket• Can he renlaced with sthis-sclient-scearch(contacts snavload) — same endhoint same recult adds 420 nrotection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():$hsAccounts = Sthis->client->qetInstance()->companies()->searchByDomain(ScompanyName, $companyProperties):• Usesvi SDK's searchByDomain which calls a search endooint — hits the search rate limit bucket• No 420 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or "" for commands...
|
10182
|
NULL
|
NULL
|
NULL
|
|
10183
|
NULL
|
0
|
2026-05-08T17:08:31.218388+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260111218_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCK NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCKER₴1DEV (docker)982JY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPAPP (-zsh)-zshJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20725-handle-HS-search-rate-limitSwitched to a new branch 'JY-20725-handle-HS-search-rate-limit'Lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ I‹ >0 lobl100% C8• ₴4|screenpipe*•$5-zshFri 8 May 20:08:31T81₴6APP...
|
NULL
|
-6803604755603377971
|
NULL
|
idle
|
ocr
|
NULL
|
NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCK NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCKER₴1DEV (docker)982JY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPAPP (-zsh)-zshJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20725-handle-HS-search-rate-limitSwitched to a new branch 'JY-20725-handle-HS-search-rate-limit'Lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ I‹ >0 lobl100% C8• ₴4|screenpipe*•$5-zshFri 8 May 20:08:31T81₴6APP...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10182
|
NULL
|
0
|
2026-05-08T17:08:30.813177+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260110813_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionFileEdiVIeWMistonWindowheltCode diff reviewo NotionFileEdiVIeWMistonWindowheltCode diff reviewopen separate tickets for them rather than expand thswitch cursor() to lazyByid(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dur dre-care uis rr ana ve lone in sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccoctod throo Iaraval itaration mothode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY id-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r elDB connection: held open and busy for the entire iteWrite a message…Pull requests • screenpipe/screenpipe • GitHubHome I Hostinger@ Login - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tab• github.com/screenpipe/screenpipe/pulls?page=2&¢PatformvSolutionsPesources# screenoioe /screenbioe (Publio‹> Code• Issues 16Pull requests• isX Cl881881L Lukas Kovalik's No..100% 12rho May 20:00.30Edited 2h ago*...n Homea Testb DailyAgents+ New agentWorkspace* Quick Note- Work• Jira ticketView of Sprint17 DailyPlan7 SprintStefka 1-11 Todoã devEvaluationKnowledaem IdeasE Home viewsA Integration-appWork Knowledaetesting keyboard4 Todo5 YEAR 2026[ New page(9 New pagePersonal Home1 LOGSBudaet2 ApartmánRouterª) Population decline explained1 Seniority LevelsПП Martila Interview Preparation(9 Pain Trackel7 New chat x0Work Knowledgee Hubspot / Hubspot APl callsnulvio vynunivinvourtuiConUuUrtMINMethodVia executeRequest/?Rate Limitclient->getOwnersArchived) →makekequestexecute()ANO4 RUPSTapp/services Activity Hubspot/service.phpunis service uses >thisoercrmService->searchCallsForPeriod).(the CRM Service.php) - it makes no direct HubSpot API calls itself. All calls delegate through crmService->getCall()Critical Findings1. Line 1313 — raw searchApi()->doSearch() - matchExactlyByParticipant() in Service.php:$response = sthis->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completelv around the Cllent wrapper — no 429 handlina, no RateLim1tException, no rate limit awareness• Uses the search rate limit bucket• Can be replaced with Sthis->client->search(contacts, Spayload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():$hsAccounts = Sthis->client->qetInstance()->companies()->searchByDomain(ScompanyName, $companyProperties):• Usesvi SDK's searchByDomain which calls a search endooint — hits the search rate limit bucket• No 420 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or "" for commands...
|
NULL
|
-4881519568567508494
|
NULL
|
idle
|
ocr
|
NULL
|
NotionFileEdiVIeWMistonWindowheltCode diff reviewo NotionFileEdiVIeWMistonWindowheltCode diff reviewopen separate tickets for them rather than expand thswitch cursor() to lazyByid(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dur dre-care uis rr ana ve lone in sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccoctod throo Iaraval itaration mothode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY id-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r elDB connection: held open and busy for the entire iteWrite a message…Pull requests • screenpipe/screenpipe • GitHubHome I Hostinger@ Login - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tab• github.com/screenpipe/screenpipe/pulls?page=2&¢PatformvSolutionsPesources# screenoioe /screenbioe (Publio‹> Code• Issues 16Pull requests• isX Cl881881L Lukas Kovalik's No..100% 12rho May 20:00.30Edited 2h ago*...n Homea Testb DailyAgents+ New agentWorkspace* Quick Note- Work• Jira ticketView of Sprint17 DailyPlan7 SprintStefka 1-11 Todoã devEvaluationKnowledaem IdeasE Home viewsA Integration-appWork Knowledaetesting keyboard4 Todo5 YEAR 2026[ New page(9 New pagePersonal Home1 LOGSBudaet2 ApartmánRouterª) Population decline explained1 Seniority LevelsПП Martila Interview Preparation(9 Pain Trackel7 New chat x0Work Knowledgee Hubspot / Hubspot APl callsnulvio vynunivinvourtuiConUuUrtMINMethodVia executeRequest/?Rate Limitclient->getOwnersArchived) →makekequestexecute()ANO4 RUPSTapp/services Activity Hubspot/service.phpunis service uses >thisoercrmService->searchCallsForPeriod).(the CRM Service.php) - it makes no direct HubSpot API calls itself. All calls delegate through crmService->getCall()Critical Findings1. Line 1313 — raw searchApi()->doSearch() - matchExactlyByParticipant() in Service.php:$response = sthis->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completelv around the Cllent wrapper — no 429 handlina, no RateLim1tException, no rate limit awareness• Uses the search rate limit bucket• Can be replaced with Sthis->client->search(contacts, Spayload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():$hsAccounts = Sthis->client->qetInstance()->companies()->searchByDomain(ScompanyName, $companyProperties):• Usesvi SDK's searchByDomain which calls a search endooint — hits the search rate limit bucket• No 420 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or "" for commands...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10181
|
465
|
13
|
2026-05-08T17:08:00.137040+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260080137_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCK NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCKERDEV (docker)982JY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPAPP (-zsh)-zshJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20725-handle-HS-search-rate-limitSwitched to a new branch 'JY-20725-handle-HS-search-rate-limit'Lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ I‹ >0 lobl100% C8Fri 8 May 20:08:00• 84screenpipe*•$5-zsh₴6APP...
|
NULL
|
-4978608226304301832
|
NULL
|
idle
|
ocr
|
NULL
|
NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCK NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCKERDEV (docker)982JY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPAPP (-zsh)-zshJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20725-handle-HS-search-rate-limitSwitched to a new branch 'JY-20725-handle-HS-search-rate-limit'Lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ I‹ >0 lobl100% C8Fri 8 May 20:08:00• 84screenpipe*•$5-zsh₴6APP...
|
10179
|
NULL
|
NULL
|
NULL
|
|
10180
|
466
|
12
|
2026-05-08T17:07:59.876849+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260079876_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionFileEdiVIeWmistonWindowheltCode diff reviewo NotionFileEdiVIeWmistonWindowheltCode diff reviewopen separate tickets for them rather than expand thswitch cursor() to lazyByid(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dur dre-care uis rr ana ve lone in sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccoctod throo Iaraval itaration mothode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY id-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r elDB connection: held open and busy for the entire iteWrite a message…Pull requests • screenpipe/screenpipe • GitHubHome I Hostinger@ Login - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tab• github.com/screenpipe/screenpipe/pulls?page=2&¢PatformvSolutionsPesources# screenoioe /screenbioe (Publio‹> Code• Issues 16Pull requests• isX Cl881881L Lukas Kovalik's No..100% 12rho may 20:0/:09Edited 2h ago*...n Homea Testb DailyAgents+ New agentWorkspace* Quick Note- Work• Jira ticketView of Sprint17 DailyPlan7 SprintStefka 1-11 Todoã devEvaluationKnowledaem IdeasE Home viewsA Integration-appWork Knowledaetesting keyboard4 Todo5 YEAR 2026[ New page(9 New pagePersonal Home1 LOGSBudaet2 ApartmánRouterª) Population decline explained1 Seniority LevelsПП Martila Interview Preparation(9 Pain TrackelNew SeN7 New chat x0Work Knowledgee Hubspot / Hubspot APl callsnulvio vynunivinvourtuiConUuUrtMINMethodVia executeRequest/?Rate Limitclient->getOwnersArchived) →makekequestexecute()ANO4 RUPSTapp/services Activity Hubspot/service.phpunis service uses >thisoercrmService->searchCallsForPeriod).(the CRM Service.php) - it makes no direct HubSpot API calls itself. All calls delegate through crmService->getCall()Critical Findings1. Line 1313 — raw searchApi()->doSearch() - matchExactlyByParticipant() in Service.php:$response = sthis->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completelv around the Cllent wrapper — no 429 handlina, no RateLim1tException, no rate limit awareness• Uses the search rate limit bucket• Can be replaced with Sthis->client->search(contacts, Spayload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():$hsAccounts = Sthis->client->qetInstance()->companies()->searchByDomain(ScompanyName, $companyProperties):• Usesvi SDK's searchByDomain which calls a search endooint — hits the search rate limit bucket• No 420 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or "" for commands...
|
NULL
|
1834606348821560549
|
NULL
|
idle
|
ocr
|
NULL
|
NotionFileEdiVIeWmistonWindowheltCode diff reviewo NotionFileEdiVIeWmistonWindowheltCode diff reviewopen separate tickets for them rather than expand thswitch cursor() to lazyByid(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dur dre-care uis rr ana ve lone in sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccoctod throo Iaraval itaration mothode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY id-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r elDB connection: held open and busy for the entire iteWrite a message…Pull requests • screenpipe/screenpipe • GitHubHome I Hostinger@ Login - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tab• github.com/screenpipe/screenpipe/pulls?page=2&¢PatformvSolutionsPesources# screenoioe /screenbioe (Publio‹> Code• Issues 16Pull requests• isX Cl881881L Lukas Kovalik's No..100% 12rho may 20:0/:09Edited 2h ago*...n Homea Testb DailyAgents+ New agentWorkspace* Quick Note- Work• Jira ticketView of Sprint17 DailyPlan7 SprintStefka 1-11 Todoã devEvaluationKnowledaem IdeasE Home viewsA Integration-appWork Knowledaetesting keyboard4 Todo5 YEAR 2026[ New page(9 New pagePersonal Home1 LOGSBudaet2 ApartmánRouterª) Population decline explained1 Seniority LevelsПП Martila Interview Preparation(9 Pain TrackelNew SeN7 New chat x0Work Knowledgee Hubspot / Hubspot APl callsnulvio vynunivinvourtuiConUuUrtMINMethodVia executeRequest/?Rate Limitclient->getOwnersArchived) →makekequestexecute()ANO4 RUPSTapp/services Activity Hubspot/service.phpunis service uses >thisoercrmService->searchCallsForPeriod).(the CRM Service.php) - it makes no direct HubSpot API calls itself. All calls delegate through crmService->getCall()Critical Findings1. Line 1313 — raw searchApi()->doSearch() - matchExactlyByParticipant() in Service.php:$response = sthis->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completelv around the Cllent wrapper — no 429 handlina, no RateLim1tException, no rate limit awareness• Uses the search rate limit bucket• Can be replaced with Sthis->client->search(contacts, Spayload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():$hsAccounts = Sthis->client->qetInstance()->companies()->searchByDomain(ScompanyName, $companyProperties):• Usesvi SDK's searchByDomain which calls a search endooint — hits the search rate limit bucket• No 420 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or "" for commands...
|
10178
|
NULL
|
NULL
|
NULL
|
|
10179
|
465
|
12
|
2026-05-08T17:07:28.618425+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260048618_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCK NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCKER-₴81DEV (docker)982JY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPAPP (-zsh)-zshJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20725-handle-HS-search-rate-limitSwitched to a new branch 'JY-20725-handle-HS-search-rate-limit'Lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ I‹ >0 lobl100% C8• 84|screenpipe*•$5-zshFri 8 May 20:07:29T81₴6APP...
|
NULL
|
8495968282794932783
|
NULL
|
visual_change
|
ocr
|
NULL
|
NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCK NotionFileEditViewHistoryWindowHelp•APP (-zsh)DOCKER-₴81DEV (docker)982JY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPAPP (-zsh)-zshJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20725-handle-HS-search-rate-limitSwitched to a new branch 'JY-20725-handle-HS-search-rate-limit'Lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ I‹ >0 lobl100% C8• 84|screenpipe*•$5-zshFri 8 May 20:07:29T81₴6APP...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10178
|
466
|
11
|
2026-05-08T17:07:28.227474+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260048227_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionFileEdiVIeWMistonWindowheltCode diff reviewo NotionFileEdiVIeWMistonWindowheltCode diff reviewopen separate tickets for them rather than expand thswitch cursor() to lazyByid(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dur dre-care uis rr ana ve lone in sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccoctod throo Iaraval itaration mothode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY id-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r elDB connection: held open and busy for the entire iteWrite a message…Pull requests • screenpipe/screenpipe • GitHubHome I HostingerLogin - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tab• github.com/screenpipe/screenpipe/pulls?page=2&¢PatformvSolutionsPesources# screenoioe /screenbioe (Publio‹> Code• Issues 16Pull requests• isX Cl881881L Lukas Kovalik's No..100% 12Fri 8 May 20:07:29Edited 2h ago*...n Homea Testb DailyAgents+ New agentWorkspace* Quick Note- Work• Jira ticketView of Sprint17 DailyPlan7 SprintStefka 1-11 Todoã devEvaluationKnowledaem IdeasE Home viewsA Integration-appWork Knowledaetesting keyboard4 Todo5 YEAR 2026[ New page(9 New pagePersonal Home1 LOGSBudaet2 Apartmán@ Routerª) Population decline explained1 Seniority LevelsПП Martila Interview Preparation(9 Pain Trackel7 New chat x0Work Knowledgee Hubspot / Hubspot APl callsnulvio vynunivinvourtuiConUuUrtMINMethodVia executeRequest/?Rate Limitclient->getOwnersArchived) →makekequestexecute()ANO4 RUPSTapp/services Activity Hubspot/service.phpunis service uses >thisoercrmService->searchCallsForPeriod).(the CRM Service.php) - it makes no direct HubSpot API calls itself. All calls delegate through crmService->getCall()Critical Findings1. Line 1313 — raw searchApi()->doSearch() - matchExactlyByParticipant() in Service.php:$response = sthis->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completelv around the Cllent wrapper — no 429 handlina, no RateLim1tException, no rate limit awareness• Uses the search rate limit bucket• Can be replaced with Sthis->client->search(contacts, Spayload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():$hsAccounts = Sthis->client->qetInstance()->companies()->searchByDomain(ScompanyName, $companyProperties):• Usesvi SDK's searchByDomain which calls a search endooint — hits the search rate limit bucket• No 420 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or "' for commands...
|
NULL
|
3833531292747424656
|
NULL
|
visual_change
|
ocr
|
NULL
|
NotionFileEdiVIeWMistonWindowheltCode diff reviewo NotionFileEdiVIeWMistonWindowheltCode diff reviewopen separate tickets for them rather than expand thswitch cursor() to lazyByid(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dur dre-care uis rr ana ve lone in sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccoctod throo Iaraval itaration mothode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY id-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r elDB connection: held open and busy for the entire iteWrite a message…Pull requests • screenpipe/screenpipe • GitHubHome I HostingerLogin - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tab• github.com/screenpipe/screenpipe/pulls?page=2&¢PatformvSolutionsPesources# screenoioe /screenbioe (Publio‹> Code• Issues 16Pull requests• isX Cl881881L Lukas Kovalik's No..100% 12Fri 8 May 20:07:29Edited 2h ago*...n Homea Testb DailyAgents+ New agentWorkspace* Quick Note- Work• Jira ticketView of Sprint17 DailyPlan7 SprintStefka 1-11 Todoã devEvaluationKnowledaem IdeasE Home viewsA Integration-appWork Knowledaetesting keyboard4 Todo5 YEAR 2026[ New page(9 New pagePersonal Home1 LOGSBudaet2 Apartmán@ Routerª) Population decline explained1 Seniority LevelsПП Martila Interview Preparation(9 Pain Trackel7 New chat x0Work Knowledgee Hubspot / Hubspot APl callsnulvio vynunivinvourtuiConUuUrtMINMethodVia executeRequest/?Rate Limitclient->getOwnersArchived) →makekequestexecute()ANO4 RUPSTapp/services Activity Hubspot/service.phpunis service uses >thisoercrmService->searchCallsForPeriod).(the CRM Service.php) - it makes no direct HubSpot API calls itself. All calls delegate through crmService->getCall()Critical Findings1. Line 1313 — raw searchApi()->doSearch() - matchExactlyByParticipant() in Service.php:$response = sthis->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completelv around the Cllent wrapper — no 429 handlina, no RateLim1tException, no rate limit awareness• Uses the search rate limit bucket• Can be replaced with Sthis->client->search(contacts, Spayload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():$hsAccounts = Sthis->client->qetInstance()->companies()->searchByDomain(ScompanyName, $companyProperties):• Usesvi SDK's searchByDomain which calls a search endooint — hits the search rate limit bucket• No 420 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or "' for commands...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10177
|
465
|
11
|
2026-05-08T17:07:25.275072+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260045275_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
NotionFileEditViewHistoryWindowHelpLukás Koválik NotionFileEditViewHistoryWindowHelpLukás Koválik's No...PrcGPWork KnowledgeHubspot API calls+3 Hubspot / Hubspot API calls‹ 40alal100% <Fri 8 May 20:07:25•n Home1000TestDailyAgents+ New agentWorkspace& Quick NoteWorkJira ticketView of SprintDailyPlanSprintStefka 1-1TododevEvaluationKnowledgera IdeasPrivateE Home viewsIntegration-appWork Knowledgetesting keyboard4Todo2 New chat x0Edited 2h ago8 Share ~* ...Critical Findings1. Line 1313 - rawsearchApi()->doSearch()- matchExactlyByParticipant() in Service.php:Sresponse = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completely around the Client wrapper - no 429 handling, noRateLimitException, no rate limit awareness• Uses the search rate limit bucket• Can be replaced with Sthis->client->search('contacts', $payload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():ShsAccounts = $this->client->getInstance()->companies()->searchByDomain($companyName, $companyProperties);• Uses v1 SDK's searchByDomain which calls a search endpoint - hits the search rate limit bucket• No 429 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or 'l' for commands...
|
NULL
|
-1822988917587819003
|
NULL
|
click
|
ocr
|
NULL
|
NotionFileEditViewHistoryWindowHelpLukás Koválik NotionFileEditViewHistoryWindowHelpLukás Koválik's No...PrcGPWork KnowledgeHubspot API calls+3 Hubspot / Hubspot API calls‹ 40alal100% <Fri 8 May 20:07:25•n Home1000TestDailyAgents+ New agentWorkspace& Quick NoteWorkJira ticketView of SprintDailyPlanSprintStefka 1-1TododevEvaluationKnowledgera IdeasPrivateE Home viewsIntegration-appWork Knowledgetesting keyboard4Todo2 New chat x0Edited 2h ago8 Share ~* ...Critical Findings1. Line 1313 - rawsearchApi()->doSearch()- matchExactlyByParticipant() in Service.php:Sresponse = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completely around the Client wrapper - no 429 handling, noRateLimitException, no rate limit awareness• Uses the search rate limit bucket• Can be replaced with Sthis->client->search('contacts', $payload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():ShsAccounts = $this->client->getInstance()->companies()->searchByDomain($companyName, $companyProperties);• Uses v1 SDK's searchByDomain which calls a search endpoint - hits the search rate limit bucket• No 429 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or 'l' for commands...
|
10175
|
NULL
|
NULL
|
NULL
|
|
10176
|
466
|
10
|
2026-05-08T17:07:25.158559+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260045158_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
rirero,Code diff reviewPronllesopen separate ticke rirero,Code diff reviewPronllesopen separate tickets for them rather than expand th•••0Pull requests • screenpipe/screenpipe • GitHubHome I Hostinger@ Login - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tabswitch cursor) to lazyByld(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dut dre-care tis er ana ve one sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccostod throo Iaraval itaration mathode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY id-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r 1 elDB connection: held open and busy for the entire iteWrite a message…elnuo.com/screenolpe/screenolpe/oulls.oage=zxc=is/o5AortiS/osAcloseoPatformvSolutions vRecourcesvOpen Source vEnterprise vPricing# screenoioe /screenbioe (Publio‹> Code• Issues 16. Pull requests 17Discussions• Actionsi Projects© Security and quality• is:pr is:closedX Clear current search query. filters, and sortsi 17 Open 1.593 Closed8 docs (testing): add 3 recent regression test entrieswas closed 3 davs aco • Review required& testing: update spec from recent changes (2026-05-04)#3223 by louis030195 Co88 fix: add circuit breaker for corrupted segmentation model88 docs(testing): add a1ly multi-line bbox regression entry?x fixe add diaanostic loadina for audio device confiauration selection#3220 bv louis030195 Colla} docs: improve SEO titles across generic pages#3219 by mintlifyBot wasmerged 4 davs ago • Review requiredix chanaeloa: week of mav 3, 2026#3218 bv rifyBot was closed 3 davs ago • Review required88 docs(testing): add multi-line text bbox capture regression testii docs(testina): add Windows GetWindowRect bounds rearession test} Fix devcontainer carao path} fix(settinas): ani kev recenerate cancel. avolv button. manual editi8 docs(testina): add VACUUM INTO snapshot rearession entrvfo fix(chat): allow innut chio to be removed"whlanwthienoronehntamithp wos morhoriroudhibl• Search or jump to.100% 5Sign in* Fork 1.7krilo May 20:0/.4Sign up# Star 18.6k~ InsightsAuthor+Label+Proiects +• Labels 43• Milestones 0Milestones +Reviews +NotificationsNew oull requestAssianee +Sort11101...
|
NULL
|
8215350738971622949
|
NULL
|
click
|
ocr
|
NULL
|
rirero,Code diff reviewPronllesopen separate ticke rirero,Code diff reviewPronllesopen separate tickets for them rather than expand th•••0Pull requests • screenpipe/screenpipe • GitHubHome I Hostinger@ Login - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tabswitch cursor) to lazyByld(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dut dre-care tis er ana ve one sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccostod throo Iaraval itaration mathode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY id-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r 1 elDB connection: held open and busy for the entire iteWrite a message…elnuo.com/screenolpe/screenolpe/oulls.oage=zxc=is/o5AortiS/osAcloseoPatformvSolutions vRecourcesvOpen Source vEnterprise vPricing# screenoioe /screenbioe (Publio‹> Code• Issues 16. Pull requests 17Discussions• Actionsi Projects© Security and quality• is:pr is:closedX Clear current search query. filters, and sortsi 17 Open 1.593 Closed8 docs (testing): add 3 recent regression test entrieswas closed 3 davs aco • Review required& testing: update spec from recent changes (2026-05-04)#3223 by louis030195 Co88 fix: add circuit breaker for corrupted segmentation model88 docs(testing): add a1ly multi-line bbox regression entry?x fixe add diaanostic loadina for audio device confiauration selection#3220 bv louis030195 Colla} docs: improve SEO titles across generic pages#3219 by mintlifyBot wasmerged 4 davs ago • Review requiredix chanaeloa: week of mav 3, 2026#3218 bv rifyBot was closed 3 davs ago • Review required88 docs(testing): add multi-line text bbox capture regression testii docs(testina): add Windows GetWindowRect bounds rearession test} Fix devcontainer carao path} fix(settinas): ani kev recenerate cancel. avolv button. manual editi8 docs(testina): add VACUUM INTO snapshot rearession entrvfo fix(chat): allow innut chio to be removed"whlanwthienoronehntamithp wos morhoriroudhibl• Search or jump to.100% 5Sign in* Fork 1.7krilo May 20:0/.4Sign up# Star 18.6k~ InsightsAuthor+Label+Proiects +• Labels 43• Milestones 0Milestones +Reviews +NotificationsNew oull requestAssianee +Sort11101...
|
10174
|
NULL
|
NULL
|
NULL
|
|
10175
|
465
|
10
|
2026-05-08T17:07:22.472915+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260042472_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowLukás Koválik' SlackFileEditViewGoHistoryWindowLukás Koválik's No...ProGPWork KnowledgeHelpHubspot API calls+3 Hubspot / Hubspot API calls‹ 40alal100% <•Fri 8 May 20:07:22n Home1000TestDailyAgents+ New agentWorkspace* Quick NoteWorkJira ticketView of SprintDailyPlanSprintStefka 1-1TododevEvaluationKnowledgera IdeasPrivateE Home viewsIntegration-appWork Knowledgetesting keyboard4Todo2 New chat x0Edited 2h ago8 Share ~* ...Critical Findings1. Line 1313 - rawsearchApi()->doSearch()- matchExactlyByParticipant() in Service.php:Sresponse = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completely around the Client wrapper - no 429 handling, noRateLimitException, no rate limit awareness• Uses the search rate limit bucket• Can be replaced with Sthis->client->search('contacts', $payload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():ShsAccounts = $this->client->getInstance()->companies()->searchByDomain($companyName, $companyProperties);• Uses v1 SDK's searchByDomain which calls a search endpoint - hits the search rate limit bucket• No 429 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or 'l' for commands...
|
NULL
|
-692292702155350059
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowLukás Koválik' SlackFileEditViewGoHistoryWindowLukás Koválik's No...ProGPWork KnowledgeHelpHubspot API calls+3 Hubspot / Hubspot API calls‹ 40alal100% <•Fri 8 May 20:07:22n Home1000TestDailyAgents+ New agentWorkspace* Quick NoteWorkJira ticketView of SprintDailyPlanSprintStefka 1-1TododevEvaluationKnowledgera IdeasPrivateE Home viewsIntegration-appWork Knowledgetesting keyboard4Todo2 New chat x0Edited 2h ago8 Share ~* ...Critical Findings1. Line 1313 - rawsearchApi()->doSearch()- matchExactlyByParticipant() in Service.php:Sresponse = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);• Goes completely around the Client wrapper - no 429 handling, noRateLimitException, no rate limit awareness• Uses the search rate limit bucket• Can be replaced with Sthis->client->search('contacts', $payload) - same endpoint, same result, adds 429 protection2. Line 920-923 — companies()->searchByDomain() - matchByDomain():ShsAccounts = $this->client->getInstance()->companies()->searchByDomain($companyName, $companyProperties);• Uses v1 SDK's searchByDomain which calls a search endpoint - hits the search rate limit bucket• No 429 protection• Cannot be trivially replaced with client->search() (different endpoint/format), but could be wrapped in executeRequest()Press 'space' for Al or 'l' for commands...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10174
|
466
|
9
|
2026-05-08T17:07:21.960622+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260041960_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
rirero,Code diff reviewPronllesopen separate ticke rirero,Code diff reviewPronllesopen separate tickets for them rather than expand th•••0Pull requests • screenpipe/screenpipe • GitHubHome I Hostinger@ Login - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tabswitch cursor) to lazyByld(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dut dre-care tis er ana ve one sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccostod throo Iaraval itaration mathode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY id-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r 1 elDB connection: held open and busy for the entire iteWrite a message…elnuo.com/screenolpe/screenolpe/oulls.oage=zxc=is/o5AortiS/osAcloseoPatformvSolutions vRecourcesvOpen Source vEnterprise vPricing# screenoioe /screenbioe (Publio‹> Code• Issues 16. Pull requests 17Discussions• Actionsi Projects© Security and quality• is:pr is:closedX Clear current search query. filters, and sortsi 17 Open 1.593 Closed8 docs (testing): add 3 recent regression test entrieswas closed 3 davs aco • Review required& testing: update spec from recent changes (2026-05-04)#3223 by louis030195 Co88 fix: add circuit breaker for corrupted segmentation model88 docs(testing): add a1ly multi-line bbox regression entry?x fixe add diaanostic loadina for audio device confiauration selection#3220 bv louis030195 Colla} docs: improve SEO titles across generic pages#3219 by mintlifyBot wasmerged 4 davs ago • Review requiredix chanaeloa: week of mav 3, 2026#3218 bv rifyBot was closed 3 davs ago • Review required88 docs(testing): add multi-line text bbox capture regression testii docs(testina): add Windows GetWindowRect bounds rearession test} Fix devcontainer carao path} fix(settinas): ani kev recenerate cancel. avolv button. manual editi8 docs(testina): add VACUUM INTO snapshot rearession entrvfo fix(chat): allow innut chio to be removed"whlanwthienoronehntamithp wos morhoriroudhibl• Search or jump to.100% 5Sign in* Fork 1.7kriio May 20:0/-L4Sign up# Star 18.6k~ InsightsAuthor+Label+Proiects +• Labels 43• Milestones 0Milestones +Reviews +NotificationsNew oull requestAssianee +Sort11101...
|
NULL
|
-5902924604389431414
|
NULL
|
click
|
ocr
|
NULL
|
rirero,Code diff reviewPronllesopen separate ticke rirero,Code diff reviewPronllesopen separate tickets for them rather than expand th•••0Pull requests • screenpipe/screenpipe • GitHubHome I Hostinger@ Login - Nginx Proxy ManagelScreenpipe — Archive( SQLite Web: archive.dbSQLite Web: db.sqlite(0 screenoioel claude/skilis at main • screenoioe/screend) DXP4800PLUS-B5F8V Оптичен интернет за лома - EON телевизия | VivaciNew Tabswitch cursor) to lazyByld(250) . It preservesthnew veision wnlerestonne crover Datenea eacer 10agetindexableAttributes() )and releasingtheDBclong-held PDO connections during ES/Sentry calls)une orner uwo concers raised ov ue reviewer — uni$documentsToUpdate / $documentsToDelete,ands— are vala dut dre-care tis er ana ve one sedaraok lets fully understand chunkByldDnot sure l am fully clear on the issuethe changeDiccostod throo Iaraval itaration mathode and thoir momorGood instinct — let's actuallv understand what eachthe difterences only make sense once vou see the quecursoroUnder the hood, this runs one query and uses PDO'sMvSOLMariaDB that means P00: :MYSOL ATTR USEtells the server "send me rows as I ask for them." andserver-side until voul ve consumed it all or the conneWhat you get:SELECT * FROM activities WHERE... ORDER BY id-- A this query stavs "active" on the connectiPHP memory: only the current row's hydrated r 1 elDB connection: held open and busy for the entire iteWrite a message…elnuo.com/screenolpe/screenolpe/oulls.oage=zxc=is/o5AortiS/osAcloseoPatformvSolutions vRecourcesvOpen Source vEnterprise vPricing# screenoioe /screenbioe (Publio‹> Code• Issues 16. Pull requests 17Discussions• Actionsi Projects© Security and quality• is:pr is:closedX Clear current search query. filters, and sortsi 17 Open 1.593 Closed8 docs (testing): add 3 recent regression test entrieswas closed 3 davs aco • Review required& testing: update spec from recent changes (2026-05-04)#3223 by louis030195 Co88 fix: add circuit breaker for corrupted segmentation model88 docs(testing): add a1ly multi-line bbox regression entry?x fixe add diaanostic loadina for audio device confiauration selection#3220 bv louis030195 Colla} docs: improve SEO titles across generic pages#3219 by mintlifyBot wasmerged 4 davs ago • Review requiredix chanaeloa: week of mav 3, 2026#3218 bv rifyBot was closed 3 davs ago • Review required88 docs(testing): add multi-line text bbox capture regression testii docs(testina): add Windows GetWindowRect bounds rearession test} Fix devcontainer carao path} fix(settinas): ani kev recenerate cancel. avolv button. manual editi8 docs(testina): add VACUUM INTO snapshot rearession entrvfo fix(chat): allow innut chio to be removed"whlanwthienoronehntamithp wos morhoriroudhibl• Search or jump to.100% 5Sign in* Fork 1.7kriio May 20:0/-L4Sign up# Star 18.6k~ InsightsAuthor+Label+Proiects +• Labels 43• Milestones 0Milestones +Reviews +NotificationsNew oull requestAssianee +Sort11101...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10173
|
465
|
9
|
2026-05-08T17:07:18.954629+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260038954_m1.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 3 new items - S Vasil Vasilev (DM) - Jiminny Inc - 3 new items - Slack...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:35 PM
6:05
cursor не зарежда допълннителните таблици
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:07 PM
6:06
ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:16 PM
6:06
което обезмисля цялата гимнастика
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:21 PM
6:06
ще го ревизирам с lazy loading
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:43 PM
6:06
на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
loading…...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.51180553,"top":0.08111111,"width":0.025,"height":0.04},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"bounds":{"left":0.50625,"top":0.14,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.5138889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.50625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"bounds":{"left":0.5159722,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.50625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.51111114,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51111114,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.5159722,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.50625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"bounds":{"left":0.51666665,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51666665,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.5208333,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.50625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"bounds":{"left":0.5152778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.50625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"bounds":{"left":0.5152778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.68472224,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.072222225,"height":0.011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.58819443,"top":0.15,"width":0.057638887,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.15,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.59305555,"top":0.15,"width":0.05277778,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.58819443,"top":0.18111111,"width":0.054166667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.58819443,"top":0.21222222,"width":0.034027778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.58819443,"top":0.24333334,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.58819443,"top":0.27444443,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.27444443,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.59444445,"top":0.27444443,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.58819443,"top":0.30555555,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.58819443,"top":0.33666667,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.58819443,"top":0.36777776,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.58819443,"top":0.3988889,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.3988889,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.59305555,"top":0.3988889,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.58819443,"top":0.43,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.58819443,"top":0.4611111,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.58819443,"top":0.49222222,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.49222222,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.5923611,"top":0.49222222,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.58819443,"top":0.5655556,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.5655556,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.59444445,"top":0.5655556,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.58819443,"top":0.5966667,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.58819443,"top":0.62777776,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.58819443,"top":0.6588889,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.6666667,"top":0.6588889,"width":0.013194445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.6715278,"top":0.6588889,"width":0.029861111,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.6715278,"top":0.6588889,"width":0.008333334,"height":0.02}},{"char_start":1,"char_count":13,"bounds":{"left":0.6798611,"top":0.6588889,"width":0.060416665,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.58819443,"top":0.69,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.58819443,"top":0.7211111,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":23,"bounds":{"left":0.58819443,"top":0.75222224,"width":0.016666668,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.58819443,"top":0.78333336,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.58819443,"top":0.8144444,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.58819443,"top":0.84555554,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.65555555,"top":0.84555554,"width":0.013194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.65555555,"top":0.84555554,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":2,"bounds":{"left":0.66041666,"top":0.84555554,"width":0.011805556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.58819443,"top":0.91888887,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.58819443,"top":0.95,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.71319443,"top":0.12777779,"width":0.06458333,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"bounds":{"left":0.7326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.7798611,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.79930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.85347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"bounds":{"left":0.87291664,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.87291664,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.8784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXRadioButton","text":"Pins","depth":17,"bounds":{"left":0.9,"top":0.12777779,"width":0.04236111,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pins","depth":19,"bounds":{"left":0.91944444,"top":0.14,"width":0.017361112,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.9444444,"top":0.12777779,"width":0.022916667,"height":0.04222222},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.8229167,"top":0.17666666,"width":0.05277778,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:43 PM","depth":23,"bounds":{"left":0.8090278,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52 PM","depth":24,"bounds":{"left":0.8090278,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, привет","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.07083333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:48 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хвърли моля те едно око тука","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.14444445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:49 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/app/pull/12059","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/app/pull/12059","depth":25,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:53:03 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:53","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"опитвам се да оптимизирам процеса по индексиране на активитита за ЕС","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.19305556,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:16 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.22638889,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:35 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.22430556,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8111111,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:12:58 PM","depth":23,"bounds":{"left":0.81666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:12 PM","depth":24,"bounds":{"left":0.81666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.23194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:13:17 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:13","depth":25,"bounds":{"left":0.72430557,"top":0.16222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Switch","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.033333335,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor()","depth":25,"bounds":{"left":0.7826389,"top":0.16222222,"width":0.04027778,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to","depth":24,"bounds":{"left":0.82569444,"top":0.16111112,"width":0.015277778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"lazyById(250)","depth":25,"bounds":{"left":0.84305555,"top":0.16222222,"width":0.06527778,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":". It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.22291666,"height":0.09111111},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.9111111,"top":0.15888889,"width":0.0027777778,"height":0.02}},{"char_start":1,"char_count":132,"bounds":{"left":0.7465278,"top":0.15888889,"width":0.22291666,"height":0.093333334}}],"role_description":"text"},{"role":"AXStaticText","text":"getIndexableAttributes()","depth":25,"bounds":{"left":0.74930555,"top":0.26,"width":0.12013889,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":") and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).","depth":24,"bounds":{"left":0.7465278,"top":0.25666666,"width":0.22638889,"height":0.06888889},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.87222224,"top":0.25666666,"width":0.0027777778,"height":0.02}},{"char_start":1,"char_count":108,"bounds":{"left":0.7465278,"top":0.25666666,"width":0.22638889,"height":0.06888889}}],"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.33666667,"width":0.057638887,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.33888888,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:40:06 PM","depth":23,"bounds":{"left":0.8090278,"top":0.3422222,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:40 PM","depth":24,"bounds":{"left":0.8090278,"top":0.3422222,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хм, интересна идея","depth":24,"bounds":{"left":0.7465278,"top":0.36333334,"width":0.093055554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:03 PM","depth":24,"bounds":{"left":0.72430557,"top":0.4,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"bounds":{"left":0.72430557,"top":0.4,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го проверя","depth":24,"bounds":{"left":0.7465278,"top":0.39666668,"width":0.06944445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:17 PM","depth":24,"bounds":{"left":0.72430557,"top":0.43333334,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"bounds":{"left":0.72430557,"top":0.43333334,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"така или иначе в понеделник ще иде на прод, днес не ми се рискува","depth":24,"bounds":{"left":0.7465278,"top":0.43,"width":0.22152779,"height":0.044444446},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.43,"width":0.0055555557,"height":0.02}},{"char_start":1,"char_count":64,"bounds":{"left":0.7465278,"top":0.43,"width":0.22152779,"height":0.044444446}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.48555556,"width":0.057638887,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.48777777,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 6:05:10 PM","depth":23,"bounds":{"left":0.8090278,"top":0.4911111,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05 PM","depth":24,"bounds":{"left":0.8090278,"top":0.4911111,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"мм, прав си","depth":24,"bounds":{"left":0.7465278,"top":0.51222223,"width":0.055555556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:26 PM","depth":24,"bounds":{"left":0.72430557,"top":0.54888886,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"bounds":{"left":0.72430557,"top":0.54888886,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем","depth":24,"bounds":{"left":0.7465278,"top":0.54555553,"width":0.22291666,"height":0.044444446},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.54555553,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":71,"bounds":{"left":0.7465278,"top":0.54555553,"width":0.22222222,"height":0.044444446}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:35 PM","depth":24,"bounds":{"left":0.72430557,"top":0.6066667,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"bounds":{"left":0.72430557,"top":0.6066667,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor не зарежда допълннителните таблици","depth":24,"bounds":{"left":0.7465278,"top":0.60333335,"width":0.21944444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.5688889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.5688889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.5688889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.5688889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:07 PM","depth":24,"bounds":{"left":0.72430557,"top":0.64,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"bounds":{"left":0.72430557,"top":0.64,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало","depth":24,"bounds":{"left":0.7465278,"top":0.63666666,"width":0.23472223,"height":0.06888889},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.63666666,"width":0.009027778,"height":0.02}},{"char_start":1,"char_count":107,"bounds":{"left":0.7465278,"top":0.63666666,"width":0.23472223,"height":0.06888889}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.6022222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.6022222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.6022222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.6022222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:16 PM","depth":24,"bounds":{"left":0.72430557,"top":0.7222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"bounds":{"left":0.72430557,"top":0.7222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"което обезмисля цялата гимнастика","depth":24,"bounds":{"left":0.7465278,"top":0.7188889,"width":0.17569445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.6844444,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.6844444,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.6844444,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.6844444,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:21 PM","depth":24,"bounds":{"left":0.72430557,"top":0.75555557,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"bounds":{"left":0.72430557,"top":0.75555557,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го ревизирам с lazy loading","depth":24,"bounds":{"left":0.7465278,"top":0.75222224,"width":0.14513889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.7177778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.7177778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.7177778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.7177778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:43 PM","depth":24,"bounds":{"left":0.72430557,"top":0.7888889,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"bounds":{"left":0.72430557,"top":0.7888889,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти","depth":24,"bounds":{"left":0.7465278,"top":0.78555554,"width":0.23194444,"height":0.06888889},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.78555554,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":90,"bounds":{"left":0.7465278,"top":0.78555554,"width":0.23194444,"height":0.06888889}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.7511111,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.7511111,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.7511111,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.7511111,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"bounds":{"left":0.71666664,"top":0.88,"width":0.26527777,"height":0.04222222},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"loading…","depth":11,"on_screen":false,"role_description":"text"}]...
|
-1984781178899009791
|
-1284830094648227768
|
visual_change
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:35 PM
6:05
cursor не зарежда допълннителните таблици
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:07 PM
6:06
ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:16 PM
6:06
което обезмисля цялата гимнастика
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:21 PM
6:06
ще го ревизирам с lazy loading
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:43 PM
6:06
на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
loading…
SlackFileEditViewGoHistoryWindowHelpLukás Koválik's No...ProGPHubspot API calls+n Home1000TestDailyAgents+ New agentWorkspace* Quick NoteWorkJira ticketView of SprintDailyPlanSprintStefka 1-1TododevEvaluationKnowledgera IdeasPrivateE Home viewsIntegration-appWork Knowledgetesting keyboard4TodoWork Knowledge3 Hubspot / Hubspot API callsCritical Findings+ :1. Line 1313 — raw searchApi()->doSearch()- matchEx|2 New chat x0Sresponse = $this->client->getNewInstance()->crm(• Goes completely around the Client wrapper - no 429• Uses the search rate limit bucket• Can be replaced with $this->client->search('contacts"2. Line 920-923 — companies()->searchByDomain() - m$hsAccounts = $this->client->getInstance()->compal• Uses v1 SDK's searchByDomainwhich calls a search e• No 429 protection• Cannot be trivially replaced with client->search() (diffePress 'space' for Al or 'l' for commandsHomeDMsActivityFilesLater...More40QEDJiminny ...# conrustin-cunic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Direct messagesSo Vasil Vasilevo Nikolay IvanovGalya DimitrovaAneliya Angelova, ...2 Stoyan Tanev €ã. Stefka StoyanovaC. Ves. Aneliya Angelovado James GrahamLukas Kovalik y... O#:: AppsToastJira Cloudlabl100% <•Fri 8 May 20:07:19Describe what you are looking forVasil Vasilev• MessagesAdd canvasO Files< Pins+carsoro to LazyDyia(coueipreseivesthe single-loop, gToday~-yle code in the newversion while restoring proper batched eagerloading (avoiding N+1 ongetIndexableAttributes() ) and releasing the DBconnection between chunks (avoiding long-heldPDO connections during ES/Sentry calls).Vasil Vasilev 4:40 PMхм, интересна идеяще го проверятака или иначе в понеделник ще иде на прод.днес не ми се рискуваVasil Vasilev 6:05 PMмм, прав сизадълбах по на дълбоко, и се оказва, че cursorще произведе друг проблемcursor не зарежда допълннителните таблицище стриймне моделите, но за всеки ще викапоотделно with(opportunities, leads, accounts....) ивсичко останалокоето обезмисля цялата гимнастикаще го ревизирам с lazy loadingна по малки бачове, за да спестя памет отмоделите, просто ще взема данните на няколкопЪтиMessage Vasil Vasilev+...
|
10172
|
NULL
|
NULL
|
NULL
|
|
10172
|
465
|
8
|
2026-05-08T17:07:16.958021+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260036958_m1.jpg...
|
Firefox
|
Pull requests · screenpipe/screenpipe · GitHub — P Pull requests · screenpipe/screenpipe · GitHub — Personal...
|
1
|
github.com/screenpipe/screenpipe/pulls?page=2& github.com/screenpipe/screenpipe/pulls?page=2&q=is%3Apr+is%3Aclosed...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Close tab
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to content
Skip to content
Navigation Menu
Navigation Menu
Homepage
Platform
Solutions
Resources
Open Source
Enterprise
Pricing
Pricing
Search or jump to…
Search or jump to...
Sign in
Sign in
Sign up
Sign up
Appearance settings
screenpipe
screenpipe
/
screenpipe
screenpipe
Public
You must be signed in to change notification settings
Notifications
Fork 1.7k
Fork
1.7k
You must be signed in to star a repository
Star
18.6k
Code
Code
Issues 16
Issues
16
Pull requests 17
Pull requests
17
Discussions
Discussions
Actions
Actions
Projects
Projects
Security and quality
Security and quality
Insights
Insights
Pull requests: screenpipe/screenpipe
Pull requests: screenpipe/screenpipe
is:pr is:closed
Labels 43
Labels
43
Milestones 0
Milestones
0
New pull request
New pull request
Clear current search query, filters, and sorts
Clear current search query, filters, and sorts
17 Open
17 Open
1,593 Closed
1,593 Closed
Author
Author
Label
Label
Projects
Projects
Milestones
Milestones
Reviews
Reviews
Assignee
Assignee
Sort
Sort
Pull requests list
Pull requests list
docs(testing): add 3 recent regression test entries
docs(testing): add 3 recent regression test entries
#3224 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
testing: update spec from recent changes (2026-05-04)
testing: update spec from recent changes (2026-05-04)
#3223 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add circuit breaker for corrupted segmentation model
fix: add circuit breaker for corrupted segmentation model
#3222 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add a11y multi-line bbox regression entry
docs(testing): add a11y multi-line bbox regression entry
#3221 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add diagnostic logging for audio device configuration selection
fix: add diagnostic logging for audio device configuration selection
#3220 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs: improve SEO titles across generic pages
docs: improve SEO titles across generic pages
#3219 by
mintlify
mintlify
Bot
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3218 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add multi-line text bbox capture regression test
docs(testing): add multi-line text bbox capture regression test
#3217 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Windows GetWindowRect bounds regression test
docs(testing): add Windows GetWindowRect bounds regression test
#3216 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
Fix devcontainer cargo path
Fix devcontainer cargo path
#3214 by
julpel8
julpel8
Contributor
was merged
4 days ago
•
Review required before merging
Review required
fix(settings): api key regenerate cancel, apply button, manual edit
fix(settings): api key regenerate cancel, apply button, manual edit
#3212 by
Anshgrover23
Anshgrover23
Contributor
was merged
5 days ago
•
Review required before merging
Review required
docs(testing): add VACUUM INTO snapshot regression entry
docs(testing): add VACUUM INTO snapshot regression entry
#3211 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix(chat): allow input chip to be removed
fix(chat): allow input chip to be removed
#3210 by
thisisharsh7
thisisharsh7
Contributor
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
fix: graceful fallback when segmentation model cache is invalidated
fix: graceful fallback when segmentation model cache is invalidated
#3209 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
testing: update spec from recent changes (2026-05-03)
testing: update spec from recent changes (2026-05-03)
#3208 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add empty-state navigation button regression test
docs(testing): add empty-state navigation button regression test
#3207 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: audio dedup-skip metric — prevent false health check stalls
fix: audio dedup-skip metric — prevent false health check stalls
#3206 by
louis030195
louis030195
Collaborator
was closed
2 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3204 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.009375,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.03263889,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.05590278,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.079166666,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to content","depth":6,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Navigation Menu","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Navigation Menu","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Homepage","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Platform","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Solutions","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Resources","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Source","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Enterprise","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Pricing","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pricing","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search or jump to...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sign in","depth":8,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sign in","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sign up","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sign up","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Appearance settings","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"screenpipe","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"screenpipe","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"You must be signed in to change notification settings","depth":11,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fork 1.7k","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fork","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1.7k","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"You must be signed in to star a repository","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Star","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18.6k","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Issues 16","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests 17","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Discussions","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Discussions","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Projects","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Projects","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull requests: screenpipe/screenpipe","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull requests: screenpipe/screenpipe","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"is:pr is:closed","depth":12,"on_screen":true,"value":"is:pr is:closed","help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Labels 43","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Labels","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"43","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Milestones 0","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Milestones","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"New pull request","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New pull request","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Clear current search query, filters, and sorts","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Clear current search query, filters, and sorts","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"17 Open","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17 Open","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1,593 Closed","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1,593 Closed","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Author","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Author","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Label","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Label","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Projects","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Projects","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Milestones","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Milestones","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Reviews","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Reviews","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Assignee","depth":12,"on_screen":true,"help_text":"Assignees","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Assignee","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Sort","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Sort","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull requests list","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull requests list","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add 3 recent regression test entries","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add 3 recent regression test entries","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3224 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"testing: update spec from recent changes (2026-05-04)","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"testing: update spec from recent changes (2026-05-04)","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3223 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: add circuit breaker for corrupted segmentation model","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: add circuit breaker for corrupted segmentation model","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3222 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add a11y multi-line bbox regression entry","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add a11y multi-line bbox regression entry","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3221 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: add diagnostic logging for audio device configuration selection","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: add diagnostic logging for audio device configuration selection","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3220 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs: improve SEO titles across generic pages","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs: improve SEO titles across generic pages","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3219 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"on_screen":true,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"changelog: week of may 3, 2026","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"changelog: week of may 3, 2026","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3218 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"on_screen":true,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add multi-line text bbox capture regression test","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add multi-line text bbox capture regression test","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3217 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Windows GetWindowRect bounds regression test","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Windows GetWindowRect bounds regression test","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3216 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fix devcontainer cargo path","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fix devcontainer cargo path","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3214 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"julpel8","depth":14,"on_screen":true,"help_text":"pull requests opened by julpel8","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"julpel8","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Contributor","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix(settings): api key regenerate cancel, apply button, manual edit","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(settings): api key regenerate cancel, apply button, manual edit","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3212 by","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Anshgrover23","depth":14,"on_screen":true,"help_text":"pull requests opened by Anshgrover23","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Anshgrover23","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Contributor","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5 days ago","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add VACUUM INTO snapshot regression entry","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add VACUUM INTO snapshot regression entry","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3211 by","depth":14,"bounds":{"left":0.47743055,"top":0.0,"width":0.0375,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51493055,"top":0.0,"width":0.04826389,"height":0.016666668},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51493055,"top":0.0,"width":0.04826389,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5704861,"top":0.0,"width":0.049652778,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.62743056,"top":0.0,"width":0.045833334,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.6732639,"top":0.0,"width":0.043055557,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.7190972,"top":0.0,"width":0.00625,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7253472,"top":0.0,"width":0.06284722,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7253472,"top":0.0,"width":0.06284722,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix(chat): allow input chip to be removed","depth":13,"bounds":{"left":0.47743055,"top":0.0,"width":0.2125,"height":0.02111111},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(chat): allow input chip to be removed","depth":14,"bounds":{"left":0.47743055,"top":0.0,"width":0.2125,"height":0.02111111},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3210 by","depth":14,"bounds":{"left":0.47743055,"top":0.0,"width":0.03888889,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"thisisharsh7","depth":14,"bounds":{"left":0.51631945,"top":0.0,"width":0.047222223,"height":0.016666668},"on_screen":true,"help_text":"pull requests opened by thisisharsh7","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"thisisharsh7","depth":15,"bounds":{"left":0.51631945,"top":0.0,"width":0.047222223,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Contributor","depth":16,"bounds":{"left":0.5708333,"top":0.0,"width":0.046180554,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.62430555,"top":0.0,"width":0.05,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"bounds":{"left":0.67430556,"top":0.0,"width":0.043055557,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.7201389,"top":0.0,"width":0.00625,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7263889,"top":0.0,"width":0.06284722,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7263889,"top":0.0,"width":0.06284722,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: graceful fallback when segmentation model cache is invalidated","depth":13,"bounds":{"left":0.47743055,"top":0.02111111,"width":0.35625,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: graceful fallback when segmentation model cache is invalidated","depth":14,"bounds":{"left":0.47743055,"top":0.02111111,"width":0.35625,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3209 by","depth":14,"bounds":{"left":0.47743055,"top":0.052222222,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51770836,"top":0.052222222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51770836,"top":0.052222222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5732639,"top":0.052222222,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.6302083,"top":0.052222222,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.67604166,"top":0.052222222,"width":0.043055557,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.721875,"top":0.05111111,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.728125,"top":0.05111111,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.728125,"top":0.05111111,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"testing: update spec from recent changes (2026-05-03)","depth":13,"bounds":{"left":0.47743055,"top":0.093888886,"width":0.29895833,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"testing: update spec from recent changes (2026-05-03)","depth":14,"bounds":{"left":0.47743055,"top":0.093888886,"width":0.29895833,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3208 by","depth":14,"bounds":{"left":0.47743055,"top":0.125,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51770836,"top":0.125,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51770836,"top":0.125,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5732639,"top":0.125,"width":0.05,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.6302083,"top":0.125,"width":0.046180554,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.67638886,"top":0.125,"width":0.042708334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.721875,"top":0.12388889,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.728125,"top":0.12388889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.728125,"top":0.12388889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add empty-state navigation button regression test","depth":13,"bounds":{"left":0.47743055,"top":0.16611111,"width":0.34305555,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add empty-state navigation button regression test","depth":14,"bounds":{"left":0.47743055,"top":0.16611111,"width":0.34305555,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3207 by","depth":14,"bounds":{"left":0.47743055,"top":0.19722222,"width":0.039583333,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.5170139,"top":0.19722222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.5170139,"top":0.19722222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.57256943,"top":0.19722222,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.62951386,"top":0.19722222,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.6753472,"top":0.19722222,"width":0.043055557,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.72118056,"top":0.19611111,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7274306,"top":0.19611111,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7274306,"top":0.19611111,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: audio dedup-skip metric — prevent false health check stalls","depth":13,"bounds":{"left":0.47743055,"top":0.23888889,"width":0.334375,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: audio dedup-skip metric — prevent false health check stalls","depth":14,"bounds":{"left":0.47743055,"top":0.23888889,"width":0.334375,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3206 by","depth":14,"bounds":{"left":0.47743055,"top":0.27,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51770836,"top":0.27,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51770836,"top":0.27,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5732639,"top":0.27,"width":0.049652778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.6302083,"top":0.27,"width":0.045833334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2 days ago","depth":15,"bounds":{"left":0.67604166,"top":0.27,"width":0.042708334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.72152776,"top":0.2688889,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.7277778,"top":0.2688889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.7277778,"top":0.2688889,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"changelog: week of may 3, 2026","depth":13,"bounds":{"left":0.47743055,"top":0.31111112,"width":0.171875,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"changelog: week of may 3, 2026","depth":14,"bounds":{"left":0.47743055,"top":0.31111112,"width":0.171875,"height":0.02111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3204 by","depth":14,"bounds":{"left":0.47743055,"top":0.3422222,"width":0.04027778,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"bounds":{"left":0.51770836,"top":0.3422222,"width":0.028819444,"height":0.016666668},"on_screen":false,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"bounds":{"left":0.51770836,"top":0.3422222,"width":0.028819444,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"bounds":{"left":0.5538194,"top":0.3422222,"width":0.013888889,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.57256943,"top":0.3422222,"width":0.04826389,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.62083334,"top":0.3422222,"width":0.042708334,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.66631943,"top":0.34111112,"width":0.00625,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.67256945,"top":0.34111112,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.67256945,"top":0.34111112,"width":0.06284722,"height":0.016666668},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-3359667694541439445
|
-4646648794032007652
|
click
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Close tab
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to content
Skip to content
Navigation Menu
Navigation Menu
Homepage
Platform
Solutions
Resources
Open Source
Enterprise
Pricing
Pricing
Search or jump to…
Search or jump to...
Sign in
Sign in
Sign up
Sign up
Appearance settings
screenpipe
screenpipe
/
screenpipe
screenpipe
Public
You must be signed in to change notification settings
Notifications
Fork 1.7k
Fork
1.7k
You must be signed in to star a repository
Star
18.6k
Code
Code
Issues 16
Issues
16
Pull requests 17
Pull requests
17
Discussions
Discussions
Actions
Actions
Projects
Projects
Security and quality
Security and quality
Insights
Insights
Pull requests: screenpipe/screenpipe
Pull requests: screenpipe/screenpipe
is:pr is:closed
Labels 43
Labels
43
Milestones 0
Milestones
0
New pull request
New pull request
Clear current search query, filters, and sorts
Clear current search query, filters, and sorts
17 Open
17 Open
1,593 Closed
1,593 Closed
Author
Author
Label
Label
Projects
Projects
Milestones
Milestones
Reviews
Reviews
Assignee
Assignee
Sort
Sort
Pull requests list
Pull requests list
docs(testing): add 3 recent regression test entries
docs(testing): add 3 recent regression test entries
#3224 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
testing: update spec from recent changes (2026-05-04)
testing: update spec from recent changes (2026-05-04)
#3223 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add circuit breaker for corrupted segmentation model
fix: add circuit breaker for corrupted segmentation model
#3222 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add a11y multi-line bbox regression entry
docs(testing): add a11y multi-line bbox regression entry
#3221 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add diagnostic logging for audio device configuration selection
fix: add diagnostic logging for audio device configuration selection
#3220 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs: improve SEO titles across generic pages
docs: improve SEO titles across generic pages
#3219 by
mintlify
mintlify
Bot
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3218 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add multi-line text bbox capture regression test
docs(testing): add multi-line text bbox capture regression test
#3217 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Windows GetWindowRect bounds regression test
docs(testing): add Windows GetWindowRect bounds regression test
#3216 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
Fix devcontainer cargo path
Fix devcontainer cargo path
#3214 by
julpel8
julpel8
Contributor
was merged
4 days ago
•
Review required before merging
Review required
fix(settings): api key regenerate cancel, apply button, manual edit
fix(settings): api key regenerate cancel, apply button, manual edit
#3212 by
Anshgrover23
Anshgrover23
Contributor
was merged
5 days ago
•
Review required before merging
Review required
docs(testing): add VACUUM INTO snapshot regression entry
docs(testing): add VACUUM INTO snapshot regression entry
#3211 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix(chat): allow input chip to be removed
fix(chat): allow input chip to be removed
#3210 by
thisisharsh7
thisisharsh7
Contributor
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
fix: graceful fallback when segmentation model cache is invalidated
fix: graceful fallback when segmentation model cache is invalidated
#3209 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
testing: update spec from recent changes (2026-05-03)
testing: update spec from recent changes (2026-05-03)
#3208 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add empty-state navigation button regression test
docs(testing): add empty-state navigation button regression test
#3207 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: audio dedup-skip metric — prevent false health check stalls
fix: audio dedup-skip metric — prevent false health check stalls
#3206 by
louis030195
louis030195
Collaborator
was closed
2 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3204 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10171
|
466
|
8
|
2026-05-08T17:07:16.857848+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260036857_m2.jpg...
|
Firefox
|
Pull requests · screenpipe/screenpipe · GitHub — P Pull requests · screenpipe/screenpipe · GitHub — Personal...
|
1
|
github.com/screenpipe/screenpipe/pulls?page=2& github.com/screenpipe/screenpipe/pulls?page=2&q=is%3Apr+is%3Aclosed...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Close tab
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to content
Skip to content
Navigation Menu
Navigation Menu
Homepage
Platform
Solutions
Resources
Open Source
Enterprise
Pricing
Pricing
Search or jump to…
Search or jump to...
Sign in
Sign in
Sign up
Sign up
Appearance settings
screenpipe
screenpipe
/
screenpipe
screenpipe
Public
You must be signed in to change notification settings
Notifications
Fork 1.7k
Fork
1.7k
You must be signed in to star a repository
Star
18.6k
Code
Code
Issues 16
Issues
16
Pull requests 17
Pull requests
17
Discussions
Discussions
Actions
Actions
Projects
Projects
Security and quality
Security and quality
Insights
Insights
Pull requests: screenpipe/screenpipe
Pull requests: screenpipe/screenpipe
is:pr is:closed
Labels 43
Labels
43
Milestones 0
Milestones
0
New pull request
New pull request
Clear current search query, filters, and sorts
Clear current search query, filters, and sorts
17 Open
17 Open
1,593 Closed
1,593 Closed
Author
Author
Label
Label
Projects
Projects
Milestones
Milestones
Reviews
Reviews
Assignee
Assignee
Sort
Sort
Pull requests list
Pull requests list
docs(testing): add 3 recent regression test entries
docs(testing): add 3 recent regression test entries
#3224 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
testing: update spec from recent changes (2026-05-04)
testing: update spec from recent changes (2026-05-04)
#3223 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add circuit breaker for corrupted segmentation model
fix: add circuit breaker for corrupted segmentation model
#3222 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add a11y multi-line bbox regression entry
docs(testing): add a11y multi-line bbox regression entry
#3221 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add diagnostic logging for audio device configuration selection
fix: add diagnostic logging for audio device configuration selection
#3220 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs: improve SEO titles across generic pages
docs: improve SEO titles across generic pages
#3219 by
mintlify
mintlify
Bot
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3218 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add multi-line text bbox capture regression test
docs(testing): add multi-line text bbox capture regression test
#3217 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Windows GetWindowRect bounds regression test
docs(testing): add Windows GetWindowRect bounds regression test
#3216 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
Fix devcontainer cargo path
Fix devcontainer cargo path
#3214 by
julpel8
julpel8
Contributor
was merged
4 days ago...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.36236703,"top":0.05905826,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Home | Hostinger","depth":4,"bounds":{"left":0.26097074,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home | Hostinger","depth":5,"bounds":{"left":0.27426863,"top":0.09577015,"width":0.03025266,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login – Nginx Proxy Manager","depth":4,"bounds":{"left":0.26097074,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login – Nginx Proxy Manager","depth":5,"bounds":{"left":0.27426863,"top":0.12849163,"width":0.05069814,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.26097074,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.27426863,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.26097074,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.27426863,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.26097074,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.27426863,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.26097074,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.27426863,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.26097074,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.27426863,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":4,"bounds":{"left":0.26097074,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Оптичен интернет за дома - EON телевизия | Vivacom | 5G","depth":5,"bounds":{"left":0.27426863,"top":0.32482043,"width":0.105884306,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.26379654,"top":0.34796488,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.26379654,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.27476728,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.28590426,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.29704124,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.3081782,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to content","depth":6,"bounds":{"left":0.37466756,"top":0.0518755,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"bounds":{"left":0.37466756,"top":0.05347167,"width":0.0029920214,"height":0.21468475},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Navigation Menu","depth":7,"bounds":{"left":0.37466756,"top":0.06464485,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Navigation Menu","depth":8,"bounds":{"left":0.37466756,"top":0.06743815,"width":0.038896278,"height":0.0518755},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Homepage","depth":7,"bounds":{"left":0.38530585,"top":0.06703911,"width":0.010638298,"height":0.027533919},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Platform","depth":12,"bounds":{"left":0.4012633,"top":0.06464485,"width":0.032413565,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Solutions","depth":12,"bounds":{"left":0.43367687,"top":0.06464485,"width":0.034242023,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Resources","depth":12,"bounds":{"left":0.46791887,"top":0.06464485,"width":0.03723404,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Source","depth":12,"bounds":{"left":0.50515294,"top":0.06464485,"width":0.043550532,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Enterprise","depth":12,"bounds":{"left":0.54870343,"top":0.06464485,"width":0.03656915,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Pricing","depth":12,"bounds":{"left":0.5852726,"top":0.06464485,"width":0.021941489,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pricing","depth":14,"bounds":{"left":0.58793217,"top":0.07302474,"width":0.01662234,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"bounds":{"left":0.8133311,"top":0.06863528,"width":0.10571808,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search or jump to...","depth":11,"bounds":{"left":0.8239694,"top":0.07462091,"width":0.042054523,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sign in","depth":8,"bounds":{"left":0.923371,"top":0.06783719,"width":0.02244016,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sign in","depth":9,"bounds":{"left":0.92736036,"top":0.073822826,"width":0.014461436,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sign up","depth":7,"bounds":{"left":0.94980055,"top":0.06783719,"width":0.024933511,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sign up","depth":8,"bounds":{"left":0.95412236,"top":0.073822826,"width":0.016289894,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Appearance settings","depth":9,"bounds":{"left":0.9787234,"top":0.06783719,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"screenpipe","depth":9,"bounds":{"left":0.3932846,"top":0.1245012,"width":0.032247342,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe","depth":10,"bounds":{"left":0.3932846,"top":0.1245012,"width":0.032247342,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":9,"bounds":{"left":0.4268617,"top":0.1245012,"width":0.0018284575,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"screenpipe","depth":9,"bounds":{"left":0.43001994,"top":0.1245012,"width":0.033909574,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe","depth":10,"bounds":{"left":0.43001994,"top":0.1245012,"width":0.033909574,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Public","depth":9,"bounds":{"left":0.46891624,"top":0.12809257,"width":0.011968086,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"You must be signed in to change notification settings","depth":11,"bounds":{"left":0.8615359,"top":0.12210695,"width":0.04105718,"height":0.022346368},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":12,"bounds":{"left":0.87383646,"top":0.1272945,"width":0.02443484,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fork 1.7k","depth":11,"bounds":{"left":0.90525264,"top":0.12210695,"width":0.0390625,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fork","depth":12,"bounds":{"left":0.9175532,"top":0.1272945,"width":0.009640957,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1.7k","depth":13,"bounds":{"left":0.93018615,"top":0.1272945,"width":0.007480053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"You must be signed in to star a repository","depth":11,"bounds":{"left":0.94697475,"top":0.12210695,"width":0.042386968,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Star","depth":12,"bounds":{"left":0.95927525,"top":0.1272945,"width":0.010139627,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18.6k","depth":13,"bounds":{"left":0.9724069,"top":0.1272945,"width":0.010305851,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":11,"bounds":{"left":0.38530585,"top":0.1660016,"width":0.025099734,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":13,"bounds":{"left":0.3961104,"top":0.17118914,"width":0.011469414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Issues 16","depth":11,"bounds":{"left":0.41306517,"top":0.1660016,"width":0.03956117,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":13,"bounds":{"left":0.4240359,"top":0.17118914,"width":0.013630319,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16","depth":13,"bounds":{"left":0.4429854,"top":0.17198724,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests 17","depth":11,"bounds":{"left":0.4552859,"top":0.1660016,"width":0.054022606,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":13,"bounds":{"left":0.4659242,"top":0.17118914,"width":0.02925532,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17","depth":13,"bounds":{"left":0.50016624,"top":0.17198724,"width":0.004155585,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Discussions","depth":11,"bounds":{"left":0.5119681,"top":0.1660016,"width":0.040226065,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Discussions","depth":13,"bounds":{"left":0.52327126,"top":0.17118914,"width":0.025598405,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":11,"bounds":{"left":0.55485374,"top":0.1660016,"width":0.03025266,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":13,"bounds":{"left":0.5659907,"top":0.17118914,"width":0.015957447,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Projects","depth":11,"bounds":{"left":0.58776593,"top":0.1660016,"width":0.03174867,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Projects","depth":13,"bounds":{"left":0.59890294,"top":0.17118914,"width":0.01761968,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality","depth":11,"bounds":{"left":0.6221742,"top":0.1660016,"width":0.05817819,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":13,"bounds":{"left":0.63397604,"top":0.17118914,"width":0.04255319,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":11,"bounds":{"left":0.68301195,"top":0.1660016,"width":0.03125,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":13,"bounds":{"left":0.69431514,"top":0.17118914,"width":0.016788565,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull requests: screenpipe/screenpipe","depth":10,"bounds":{"left":0.48520613,"top":0.21628092,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull requests: screenpipe/screenpipe","depth":11,"bounds":{"left":0.48520613,"top":0.22027135,"width":0.05701463,"height":0.1452514},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"is:pr is:closed","depth":12,"bounds":{"left":0.48520613,"top":0.21628092,"width":0.25731382,"height":0.025538707},"on_screen":true,"value":"is:pr is:closed","help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Labels 43","depth":12,"bounds":{"left":0.7478391,"top":0.21628092,"width":0.04338431,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Labels","depth":13,"bounds":{"left":0.75880986,"top":0.22226655,"width":0.016954787,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"43","depth":14,"bounds":{"left":0.7780917,"top":0.22386272,"width":0.0051529254,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Milestones 0","depth":12,"bounds":{"left":0.79089093,"top":0.21628092,"width":0.050199468,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Milestones","depth":13,"bounds":{"left":0.8018617,"top":0.22226655,"width":0.02642952,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":14,"bounds":{"left":0.8306183,"top":0.22386272,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"New pull request","depth":10,"bounds":{"left":0.84375,"top":0.21628092,"width":0.045711435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New pull request","depth":13,"bounds":{"left":0.8480718,"top":0.22226655,"width":0.03706782,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Clear current search query, filters, and sorts","depth":11,"bounds":{"left":0.48520613,"top":0.25618514,"width":0.10804521,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Clear current search query, filters, and sorts","depth":12,"bounds":{"left":0.49251994,"top":0.25618514,"width":0.10073138,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"17 Open","depth":12,"bounds":{"left":0.49085772,"top":0.29768556,"width":0.025598405,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17 Open","depth":13,"bounds":{"left":0.49750665,"top":0.29928172,"width":0.018949468,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1,593 Closed","depth":12,"bounds":{"left":0.52111036,"top":0.29768556,"width":0.03706782,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1,593 Closed","depth":13,"bounds":{"left":0.5277593,"top":0.29928172,"width":0.030418882,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Author","depth":12,"bounds":{"left":0.67669547,"top":0.29768556,"width":0.018450798,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Author","depth":13,"bounds":{"left":0.67669547,"top":0.29928172,"width":0.015791224,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Label","depth":12,"bounds":{"left":0.70578456,"top":0.29768556,"width":0.015458777,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Label","depth":13,"bounds":{"left":0.70578456,"top":0.29928172,"width":0.012799202,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Projects","depth":13,"bounds":{"left":0.7318817,"top":0.29768556,"width":0.021609042,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Projects","depth":14,"bounds":{"left":0.7318817,"top":0.29928172,"width":0.018949468,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Milestones","depth":13,"bounds":{"left":0.76545876,"top":0.29768556,"width":0.027094414,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Milestones","depth":14,"bounds":{"left":0.76545876,"top":0.29928172,"width":0.02443484,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Reviews","depth":13,"bounds":{"left":0.80452126,"top":0.29768556,"width":0.02144282,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Reviews","depth":14,"bounds":{"left":0.80452126,"top":0.29928172,"width":0.018783245,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Assignee","depth":12,"bounds":{"left":0.8366024,"top":0.29768556,"width":0.023603724,"height":0.016759777},"on_screen":true,"help_text":"Assignees","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Assignee","depth":13,"bounds":{"left":0.8366024,"top":0.29928172,"width":0.020944148,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Sort","depth":12,"bounds":{"left":0.8708444,"top":0.29768556,"width":0.012965426,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Sort","depth":13,"bounds":{"left":0.8708444,"top":0.29928172,"width":0.008976064,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull requests list","depth":10,"bounds":{"left":0.48553857,"top":0.32801276,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull requests list","depth":11,"bounds":{"left":0.48553857,"top":0.33080608,"width":0.03174867,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add 3 recent regression test entries","depth":13,"bounds":{"left":0.49883643,"top":0.33758977,"width":0.12732713,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add 3 recent regression test entries","depth":14,"bounds":{"left":0.49883643,"top":0.33758977,"width":0.12732713,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3224 by","depth":14,"bounds":{"left":0.49883643,"top":0.35993615,"width":0.019115692,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51795214,"top":0.35993615,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51795214,"top":0.35993615,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54454786,"top":0.35993615,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5718085,"top":0.35993615,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59391624,"top":0.35993615,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6156915,"top":0.35913807,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6186835,"top":0.35913807,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6186835,"top":0.35913807,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.3367917,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.33838788,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"testing: update spec from recent changes (2026-05-04)","depth":13,"bounds":{"left":0.49883643,"top":0.38946527,"width":0.14328457,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"testing: update spec from recent changes (2026-05-04)","depth":14,"bounds":{"left":0.49883643,"top":0.38946527,"width":0.14328457,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3223 by","depth":14,"bounds":{"left":0.49883643,"top":0.41181165,"width":0.019115692,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51795214,"top":0.41181165,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51795214,"top":0.41181165,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54454786,"top":0.41181165,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5718085,"top":0.41181165,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59391624,"top":0.41181165,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6156915,"top":0.41101357,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6186835,"top":0.41101357,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6186835,"top":0.41101357,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.38906625,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.3906624,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: add circuit breaker for corrupted segmentation model","depth":13,"bounds":{"left":0.49883643,"top":0.44173983,"width":0.14494681,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: add circuit breaker for corrupted segmentation model","depth":14,"bounds":{"left":0.49883643,"top":0.44173983,"width":0.14494681,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3222 by","depth":14,"bounds":{"left":0.49883643,"top":0.4640862,"width":0.019115692,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51795214,"top":0.4640862,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51795214,"top":0.4640862,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54454786,"top":0.4640862,"width":0.023769947,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5718085,"top":0.4640862,"width":0.021941489,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59375,"top":0.4640862,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.61552525,"top":0.4632881,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6185173,"top":0.4632881,"width":0.03025266,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6185173,"top":0.4632881,"width":0.03025266,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"bounds":{"left":0.8746675,"top":0.44094175,"width":0.009142287,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"bounds":{"left":0.8813165,"top":0.4425379,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add a11y multi-line bbox regression entry","depth":13,"bounds":{"left":0.49883643,"top":0.49401435,"width":0.14112367,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add a11y multi-line bbox regression entry","depth":14,"bounds":{"left":0.49883643,"top":0.49401435,"width":0.14112367,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3221 by","depth":14,"bounds":{"left":0.49883643,"top":0.51636076,"width":0.018450798,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51728725,"top":0.51636076,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51728725,"top":0.51636076,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54388297,"top":0.51636076,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5711436,"top":0.51636076,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59325135,"top":0.51636076,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6150266,"top":0.51556265,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6180186,"top":0.51556265,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6180186,"top":0.51556265,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.49321628,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.49481246,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"fix: add diagnostic logging for audio device configuration selection","depth":13,"bounds":{"left":0.49883643,"top":0.54588985,"width":0.16805187,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix: add diagnostic logging for audio device configuration selection","depth":14,"bounds":{"left":0.49883643,"top":0.54588985,"width":0.16805187,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3220 by","depth":14,"bounds":{"left":0.49883643,"top":0.56823623,"width":0.019115692,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51795214,"top":0.56823623,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51795214,"top":0.56823623,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.54454786,"top":0.56823623,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5718085,"top":0.56823623,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59391624,"top":0.56823623,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.6156915,"top":0.5674381,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6186835,"top":0.5674381,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6186835,"top":0.5674381,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.5454908,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.547087,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs: improve SEO titles across generic pages","depth":13,"bounds":{"left":0.49883643,"top":0.5981644,"width":0.116855055,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs: improve SEO titles across generic pages","depth":14,"bounds":{"left":0.49883643,"top":0.5981644,"width":0.116855055,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3219 by","depth":14,"bounds":{"left":0.49883643,"top":0.62051076,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"bounds":{"left":0.51745343,"top":0.62051076,"width":0.013796543,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"bounds":{"left":0.51745343,"top":0.62051076,"width":0.013796543,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"bounds":{"left":0.5347407,"top":0.62051076,"width":0.0066489363,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.5437167,"top":0.62051076,"width":0.024933511,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"bounds":{"left":0.56865025,"top":0.62051076,"width":0.020611702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.5905917,"top":0.6197127,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.59358376,"top":0.6197127,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.59358376,"top":0.6197127,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.59736633,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.5989625,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"changelog: week of may 3, 2026","depth":13,"bounds":{"left":0.49883643,"top":0.6500399,"width":0.08228058,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"changelog: week of may 3, 2026","depth":14,"bounds":{"left":0.49883643,"top":0.6500399,"width":0.08228058,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3218 by","depth":14,"bounds":{"left":0.49883643,"top":0.6723863,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"mintlify","depth":14,"bounds":{"left":0.51745343,"top":0.6723863,"width":0.013796543,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by mintlify[bot]","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"mintlify","depth":15,"bounds":{"left":0.51745343,"top":0.6723863,"width":0.013796543,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":15,"bounds":{"left":0.5347407,"top":0.6723863,"width":0.0066489363,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5437167,"top":0.6723863,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.5668218,"top":0.6723863,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.58859706,"top":0.6715882,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.5915891,"top":0.6715882,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.5915891,"top":0.6715882,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2 comments","depth":13,"bounds":{"left":0.8746675,"top":0.64964086,"width":0.009142287,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2","depth":14,"bounds":{"left":0.8813165,"top":0.651237,"width":0.002493351,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add multi-line text bbox capture regression test","depth":13,"bounds":{"left":0.49883643,"top":0.70231444,"width":0.15741356,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add multi-line text bbox capture regression test","depth":14,"bounds":{"left":0.49883643,"top":0.70231444,"width":0.15741356,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3217 by","depth":14,"bounds":{"left":0.49883643,"top":0.7246608,"width":0.018284574,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.517121,"top":0.7246608,"width":0.023271276,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.517121,"top":0.7246608,"width":0.023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5437167,"top":0.7246608,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.5711436,"top":0.7246608,"width":0.021941489,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.5930851,"top":0.7246608,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.61486036,"top":0.7238627,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.6178524,"top":0.7238627,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.6178524,"top":0.7238627,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.7015164,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.70311254,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"docs(testing): add Windows GetWindowRect bounds regression test","depth":13,"bounds":{"left":0.49883643,"top":0.75458896,"width":0.17270611,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"docs(testing): add Windows GetWindowRect bounds regression test","depth":14,"bounds":{"left":0.49883643,"top":0.75458896,"width":0.17270611,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3216 by","depth":14,"bounds":{"left":0.49883643,"top":0.77693534,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"louis030195","depth":14,"bounds":{"left":0.51745343,"top":0.77693534,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by louis030195","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"louis030195","depth":15,"bounds":{"left":0.51745343,"top":0.77693534,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Collaborator","depth":16,"bounds":{"left":0.5440492,"top":0.77693534,"width":0.023769947,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was closed","depth":14,"bounds":{"left":0.57130986,"top":0.77693534,"width":0.021941489,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3 days ago","depth":15,"bounds":{"left":0.59325135,"top":0.77693534,"width":0.020611702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":14,"bounds":{"left":0.61519283,"top":0.7761373,"width":0.0029920214,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review required before merging","depth":14,"bounds":{"left":0.61818486,"top":0.7761373,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review required","depth":15,"bounds":{"left":0.61818486,"top":0.7761373,"width":0.030086435,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1 comment","depth":13,"bounds":{"left":0.87516624,"top":0.7537909,"width":0.008643617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.88181514,"top":0.75538707,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fix devcontainer cargo path","depth":13,"bounds":{"left":0.49883643,"top":0.8064645,"width":0.0703125,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fix devcontainer cargo path","depth":14,"bounds":{"left":0.49883643,"top":0.8064645,"width":0.0703125,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#3214 by","depth":14,"bounds":{"left":0.49883643,"top":0.8288109,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"julpel8","depth":14,"bounds":{"left":0.51745343,"top":0.8288109,"width":0.012632979,"height":0.011971269},"on_screen":true,"help_text":"pull requests opened by julpel8","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"julpel8","depth":15,"bounds":{"left":0.51745343,"top":0.8288109,"width":0.012632979,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Contributor","depth":16,"bounds":{"left":0.53357714,"top":0.8288109,"width":0.022107713,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"was merged","depth":14,"bounds":{"left":0.55917555,"top":0.8288109,"width":0.023936171,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4 days ago","depth":15,"bounds":{"left":0.5831117,"top":0.8288109,"width":0.02044548,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-4344378400564324357
|
-5254599593711004132
|
click
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
Close tab
Home | Hostinger
Home | Hostinger
Login – Nginx Proxy Manager
Login – Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
Оптичен интернет за дома - EON телевизия | Vivacom | 5G
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Skip to content
Skip to content
Navigation Menu
Navigation Menu
Homepage
Platform
Solutions
Resources
Open Source
Enterprise
Pricing
Pricing
Search or jump to…
Search or jump to...
Sign in
Sign in
Sign up
Sign up
Appearance settings
screenpipe
screenpipe
/
screenpipe
screenpipe
Public
You must be signed in to change notification settings
Notifications
Fork 1.7k
Fork
1.7k
You must be signed in to star a repository
Star
18.6k
Code
Code
Issues 16
Issues
16
Pull requests 17
Pull requests
17
Discussions
Discussions
Actions
Actions
Projects
Projects
Security and quality
Security and quality
Insights
Insights
Pull requests: screenpipe/screenpipe
Pull requests: screenpipe/screenpipe
is:pr is:closed
Labels 43
Labels
43
Milestones 0
Milestones
0
New pull request
New pull request
Clear current search query, filters, and sorts
Clear current search query, filters, and sorts
17 Open
17 Open
1,593 Closed
1,593 Closed
Author
Author
Label
Label
Projects
Projects
Milestones
Milestones
Reviews
Reviews
Assignee
Assignee
Sort
Sort
Pull requests list
Pull requests list
docs(testing): add 3 recent regression test entries
docs(testing): add 3 recent regression test entries
#3224 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
testing: update spec from recent changes (2026-05-04)
testing: update spec from recent changes (2026-05-04)
#3223 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add circuit breaker for corrupted segmentation model
fix: add circuit breaker for corrupted segmentation model
#3222 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add a11y multi-line bbox regression entry
docs(testing): add a11y multi-line bbox regression entry
#3221 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
fix: add diagnostic logging for audio device configuration selection
fix: add diagnostic logging for audio device configuration selection
#3220 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs: improve SEO titles across generic pages
docs: improve SEO titles across generic pages
#3219 by
mintlify
mintlify
Bot
was merged
4 days ago
•
Review required before merging
Review required
1 comment
1
changelog: week of may 3, 2026
changelog: week of may 3, 2026
#3218 by
mintlify
mintlify
Bot
was closed
3 days ago
•
Review required before merging
Review required
2 comments
2
docs(testing): add multi-line text bbox capture regression test
docs(testing): add multi-line text bbox capture regression test
#3217 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
docs(testing): add Windows GetWindowRect bounds regression test
docs(testing): add Windows GetWindowRect bounds regression test
#3216 by
louis030195
louis030195
Collaborator
was closed
3 days ago
•
Review required before merging
Review required
1 comment
1
Fix devcontainer cargo path
Fix devcontainer cargo path
#3214 by
julpel8
julpel8
Contributor
was merged
4 days ago...
|
10169
|
NULL
|
NULL
|
NULL
|
|
10170
|
465
|
7
|
2026-05-08T17:07:12.527416+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260032527_m1.jpg...
|
Firefox
|
SevenShores\Hubspot\Exceptions\BadRequest: Client SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT — Work...
|
1
|
jiminny.sentry.io/issues/7007366572/events/e72ac6c jiminny.sentry.io/issues/7007366572/events/e72ac6ccaa9445e3ae04d55cb8c32844/?project=82419...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Unnamed Group
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Collapse
Listen
Show more options
Show thinking
Gemini said
Gemini said
Overview
Overview
This diff refactors the
LoadDocumentsAction
class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.
Architectural & Structural Changes
Architectural & Structural Changes
Dependency Injection:
Injected
EntityQueryBuilder
via the constructor instead of calling it statically.
Removed Traits & Constants:
Removed the
SkipActivityTrait
entirely (and its associated skip logic), as well as the
RDS_CHUNK_SIZE
constant.
Namespace Imports:
Added the
Throwable
import and removed
Illuminate\Support\Collection
.
Data Processing Refactor
Data Processing Refactor
Cursor Implementation:
Replaced
chunkByIdDesc
with
cursor()
, iterating through records sequentially rather than loading batches of 250 into memory.
Simplified Deletion Checks:
Replaced Laravel collection filtering (
whereNotNull('deleted_at')
) with a direct
$entityModel->isDeleted()
check on each model during iteration.
Removed Skip Logic:
Removed the
shouldSkipActivity
check, meaning all non-deleted models are now directly processed for updates.
Exception Handling:
Updated the catch block to use the imported
Throwable
interface rather than the fully qualified
\Throwable
.
Memory Optimization
Memory Optimization
Explicit Garbage Collection:
Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (
$entityModel->setRelations([])
) and unsetting the model (
unset($entityModel)
) explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.
You said
You are seasoned code reviewer and your task is to make detailed code
review of summarized page. First understand the code changes, then
evaluate it and try to find potential issues and bottlenecks.
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Code Review: LoadDocumentsAction Refactoring
Code Review:
LoadDocumentsAction
Refactoring
As requested, I have reviewed the refactoring of the
LoadDocumentsAction
class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.
Here is my detailed evaluation.
1. Strengths & Positive Changes
1. Strengths & Positive Changes
Dependency Injection:
Moving
EntityQueryBuilder
from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.
Simplified Readability:
Replacing the nested closures required by
chunkByIdDesc
with a flatter
foreach
structure makes the code easier to read and reason about.
Garbage Collection Awareness:
The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.
2. Critical Issues & Bottlenecks
2. Critical Issues & Bottlenecks
A. The "Infinite Accumulation" Memory Leak
A. The "Infinite Accumulation" Memory Leak
The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose.
The Issue:
The code iterates over the database cursor and manually unsets
$entityModel
to free memory. However, it simultaneously instantiates new
Document
objects and adds them to
$documentsToUpdate
(and IDs to
$documentsToDelete
).
The Bottleneck:
These collections are not flushed or processed within the loop; they are accumulated and returned at the end of the method. If this script processes 500,000 records,
$documentsToUpdate
will hold 500,000 ElasticSearch
Document
objects in RAM at once, inevitably leading to an Out Of Memory (OOM) fatal error.
B. Laravel cursor() and N+1 Query Problems
B. Laravel
cursor()
and N+1 Query Problems
Replacing
chunkByIdDesc()
with
cursor()
introduces a severe database performance risk.
The Issue:
Laravel's
cursor()
executes a single query and uses a PHP generator to yield results one by one via a PDO cursor. Because it does not process models in batches,
cursor()
cannot eager-load relationships.
*
The Bottleneck:
If
$entityModel->getIndexableAttributes()
relies on
any
database relationships (e.g., getting a user's company or tags), it will trigger an N+1 query. For 100,000 records, this will execute 100,001 database queries, absolutely hammering the database.
C. Long-Running PDO Connections
C. Long-Running PDO Connections
The Issue:
Because
cursor()
keeps a single database connection open while iterating through the results, any network latency encountered inside the loop extends the transaction time.
The Bottleneck:
If ElasticSearch
Document
instantiation or the Sentry API calls (on failure) take time, the PDO connection to the MariaDB database will remain open for an extended period, potentially leading to connection timeouts, blocked processes, or database lock exhaustion.
3. Minor Issues & Observations
3. Minor Issues & Observations
Missing Skip Logic:
The removal of
SkipActivityTrait
assumes these models no longer need to be bypassed. If this was an accidental omission, you will end up polluting ElasticSearch with activity logs that were previously filtered out, wasting ES storage and processing power.
Synchronous Sentry Calls:
If a specific batch of data is malformed and throws multiple
Throwable
errors consecutively,
Sentry::captureException
will make synchronous outbound HTTP calls for every failed record. This will severely degrade the throughput of the hydration process.
4. Recommendations for Refactoring
4. Recommendations for Refactoring
To resolve these issues, I recommend a hybrid approach utilizing Laravel's
lazyById()
(or returning to chunking) combined with batch-processing the ElasticSearch payloads:
Use
lazyById()
instead of
cursor()
:
* Laravel's
lazyById(250)
fetches records in chunks under the hood (allowing for eager loading of relations without N+1) but yields them as a flat generator to the
foreach
loop. This gives you the clean syntax of a generator with the safety of chunked eager loading.
Dispatch to ElasticSearch Inside the Loop:
* Do not wait until the end of the method to return massive collections.
Keep a counter. When
$documentsToUpdate
reaches a certain threshold (e.g., 500 documents), dispatch them to ElasticSearch, empty the
SimpleCollection
, and continue the loop.
Group Sentry Exceptions:
Consider implementing a circuit breaker or batching error logs so that a sudden spike in formatting errors doesn't result in thousands of synchronous API calls to Sentry.
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to main content
Skip to main content
Toggle organization menu
Issues
Issues
Explore
Explore
Dashboards
Dashboards
Monitors
Monitors
Settings
Settings
Try Business
What's New
Help
[EMAIL]
Issues
Expand
Feed
Feed
Errors & Outages
Errors & Outages
Breached Metrics
Breached Metrics
Warnings
Warnings
User Feedback
User Feedback
Autofix
Autofix
Recently Run
Recently Run
All Views
All Views
Configure
Alerts Moved
Alerts
Moved
Issues
Issues
View Project Details
APP-1EED
Ask Seer
Ask Seer
/
Give Feedback
SevenShores\Hubspot\Exceptions\BadRequest
View events...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unnamed Group","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Feed — jiminny — Sentry","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed — jiminny — Sentry","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Problem loading page","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Problem loading page","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI Features | Datadog","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI Features | Datadog","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.0013888889,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\\Component\\ES\\Processor\\Actions;5namespace Jiminny\\Component\\ES\\Processor\\Actions;667use Elastica\\Document;7use Elastica\\Document;8-use Illuminate\\Support\\Collection;9use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;8use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;10use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;9use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;11use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;10use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;12use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;11use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;13-use Jiminny\\Component\\ES\\Processor\\Traits\\SkipActivityTrait;14use Jiminny\\Exceptions\\SyncActivityException;12use Jiminny\\Exceptions\\SyncActivityException;15use Jiminny\\Models\\Model;13use Jiminny\\Models\\Model;16use Sentry\\Laravel\\Facade as Sentry;14use Sentry\\Laravel\\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\\Component\\ES\\Processor\\Actions;5namespace Jiminny\\Component\\ES\\Processor\\Actions;667use Elastica\\Document;7use Elastica\\Document;8-use Illuminate\\Support\\Collection;9use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;8use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;10use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;9use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;11use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;10use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;12use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;11use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;13-use Jiminny\\Component\\ES\\Processor\\Traits\\SkipActivityTrait;14use Jiminny\\Exceptions\\SyncActivityException;12use Jiminny\\Exceptions\\SyncActivityException;15use Jiminny\\Models\\Model;13use Jiminny\\Models\\Model;16use Sentry\\Laravel\\Facade as Sentry;14use Sentry\\Laravel\\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Overview","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Overview","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This diff refactors the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Architectural & Structural Changes","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Architectural & Structural Changes","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dependency Injection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Injected","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EntityQueryBuilder","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"via the constructor instead of calling it statically.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Traits & Constants:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SkipActivityTrait","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely (and its associated skip logic), as well as the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RDS_CHUNK_SIZE","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Namespace Imports:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"import and removed","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Illuminate\\Support\\Collection","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Data Processing Refactor","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Data Processing Refactor","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Cursor Implementation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", iterating through records sequentially rather than loading batches of 250 into memory.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Simplified Deletion Checks:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Laravel collection filtering (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"whereNotNull('deleted_at')","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") with a direct","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->isDeleted()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check on each model during iteration.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Skip Logic:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"shouldSkipActivity","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check, meaning all non-deleted models are now directly processed for updates.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Exception Handling:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the catch block to use the imported","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"interface rather than the fully qualified","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Memory Optimization","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Memory Optimization","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Explicit Garbage Collection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->setRelations([])","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and unsetting the model (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"unset($entityModel)","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You are seasoned code reviewer and your task is to make detailed code","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review of summarized page. First understand the code changes, then","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"evaluate it and try to find potential issues and bottlenecks.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Code Review: LoadDocumentsAction Refactoring","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Code Review:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactoring","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"As requested, I have reviewed the refactoring of the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is my detailed evaluation.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Strengths & Positive Changes","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Strengths & Positive Changes","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dependency Injection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Moving","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EntityQueryBuilder","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Simplified Readability:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replacing the nested closures required by","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with a flatter","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"structure makes the code easier to read and reason about.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Garbage Collection Awareness:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Critical Issues & Bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Critical Issues & Bottlenecks","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"A. The \"Infinite Accumulation\" Memory Leak","depth":23,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"A. The \"Infinite Accumulation\" Memory Leak","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The code iterates over the database cursor and manually unsets","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to free memory. However, it simultaneously instantiates new","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Document","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"objects and adds them to","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToUpdate","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(and IDs to","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToDelete","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"These collections are not flushed or processed within the loop; they are accumulated and returned at the end of the method. If this script processes 500,000 records,","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToUpdate","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"will hold 500,000 ElasticSearch","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Document","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"objects in RAM at once, inevitably leading to an Out Of Memory (OOM) fatal error.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"B. Laravel cursor() and N+1 Query Problems","depth":23,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"B. Laravel","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and N+1 Query Problems","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replacing","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc()","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"introduces a severe database performance risk.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Laravel's","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"executes a single query and uses a PHP generator to yield results one by one via a PDO cursor. Because it does not process models in batches,","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cannot eager-load relationships.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->getIndexableAttributes()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"relies on","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"any","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"database relationships (e.g., getting a user's company or tags), it will trigger an N+1 query. For 100,000 records, this will execute 100,001 database queries, absolutely hammering the database.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"C. Long-Running PDO Connections","depth":23,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"C. Long-Running PDO Connections","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Because","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"keeps a single database connection open while iterating through the results, any network latency encountered inside the loop extends the transaction time.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"bounds":{"left":0.11631945,"top":0.038333334,"width":0.08611111,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If ElasticSearch","depth":26,"bounds":{"left":0.20243056,"top":0.038333334,"width":0.083680555,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Document","depth":27,"bounds":{"left":0.12048611,"top":0.06888889,"width":0.046527777,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"instantiation or the Sentry API calls (on failure) take time, the PDO connection to the MariaDB database will remain open for an extended period, potentially leading to connection timeouts, blocked processes, or database lock exhaustion.","depth":26,"bounds":{"left":0.11631945,"top":0.06722222,"width":0.21388888,"height":0.19611111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Minor Issues & Observations","depth":23,"bounds":{"left":0.08993056,"top":0.31611112,"width":0.24027778,"height":0.026666667},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Minor Issues & Observations","depth":24,"bounds":{"left":0.08993056,"top":0.31833333,"width":0.16770834,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Missing Skip Logic:","depth":26,"bounds":{"left":0.11631945,"top":0.355,"width":0.103125,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The removal of","depth":26,"bounds":{"left":0.21944444,"top":0.355,"width":0.08020833,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SkipActivityTrait","depth":27,"bounds":{"left":0.12048611,"top":0.38555557,"width":0.099305555,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"assumes these models no longer need to be bypassed. If this was an accidental omission, you will end up polluting ElasticSearch with activity logs that were previously filtered out, wasting ES storage and processing power.","depth":26,"bounds":{"left":0.11631945,"top":0.3838889,"width":0.21145834,"height":0.19611111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Synchronous Sentry Calls:","depth":26,"bounds":{"left":0.11631945,"top":0.59833336,"width":0.14201389,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If a specific batch of data is malformed and throws multiple","depth":26,"bounds":{"left":0.11631945,"top":0.59833336,"width":0.20590279,"height":0.08055556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"bounds":{"left":0.16354166,"top":0.6577778,"width":0.052430555,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"errors consecutively,","depth":26,"bounds":{"left":0.22013889,"top":0.6561111,"width":0.110069446,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Sentry::captureException","depth":27,"bounds":{"left":0.12048611,"top":0.68666667,"width":0.13993056,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"will make synchronous outbound HTTP calls for every failed record. This will severely degrade the throughput of the hydration process.","depth":26,"bounds":{"left":0.11631945,"top":0.685,"width":0.20798612,"height":0.13833334},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. Recommendations for Refactoring","depth":23,"bounds":{"left":0.08993056,"top":0.8761111,"width":0.24027778,"height":0.026666667},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4. Recommendations for Refactoring","depth":24,"bounds":{"left":0.08993056,"top":0.87833333,"width":0.19826388,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To resolve these issues, I recommend a hybrid approach utilizing Laravel's","depth":24,"bounds":{"left":0.08993056,"top":0.915,"width":0.23506944,"height":0.051666666},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lazyById()","depth":25,"bounds":{"left":0.234375,"top":0.94555557,"width":0.058333334,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(or returning to chunking) combined with batch-processing the ElasticSearch payloads:","depth":24,"bounds":{"left":0.08993056,"top":0.9438889,"width":0.22743055,"height":0.056111097},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Use","depth":26,"bounds":{"left":0.11631945,"top":1.0,"width":0.023263888,"height":-0.042777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lazyById()","depth":27,"bounds":{"left":0.14375,"top":1.0,"width":0.058333334,"height":-0.04444444},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"instead of","depth":26,"bounds":{"left":0.20625,"top":1.0,"width":0.060069446,"height":-0.042777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"bounds":{"left":0.27048612,"top":1.0,"width":0.046527777,"height":-0.04444444},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":26,"bounds":{"left":0.32118055,"top":1.0,"width":0.0034722222,"height":-0.042777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Laravel's","depth":26,"bounds":{"left":0.11631945,"top":1.0,"width":0.21111111,"height":-0.042777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lazyById(250)","depth":27,"bounds":{"left":0.17604166,"top":1.0,"width":0.07569444,"height":-0.07333338},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"fetches records in chunks under the hood (allowing for eager loading of relations without N+1) but yields them as a flat generator to the","depth":26,"bounds":{"left":0.11631945,"top":1.0,"width":0.19652778,"height":-0.07166672},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"loop. This gives you the clean syntax of a generator with the safety of chunked eager loading.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dispatch to ElasticSearch Inside the Loop:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Do not wait until the end of the method to return massive collections.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Keep a counter. When","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToUpdate","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"reaches a certain threshold (e.g., 500 documents), dispatch them to ElasticSearch, empty the","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SimpleCollection","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and continue the loop.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Sentry Exceptions:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Consider implementing a circuit breaker or batching error logs so that a sudden spike in formatting errors doesn't result in thousands of synchronous API calls to Sentry.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":21,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":21,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Redo","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share & export","depth":20,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"on_screen":true,"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Microphone","depth":19,"on_screen":true,"role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send message","depth":19,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"bounds":{"left":0.08020833,"top":0.0,"width":0.11180556,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"bounds":{"left":0.09201389,"top":0.0,"width":0.088194445,"height":0.02111111},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to main content","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to main content","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle organization menu","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Issues","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Explore","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Explore","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dashboards","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dashboards","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Monitors","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Monitors","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Try Business","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"What's New","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Help","depth":10,"bounds":{"left":0.3670139,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"lukas.kovalik@jiminny.com","depth":10,"bounds":{"left":0.3670139,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Issues","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Feed","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Errors & Outages","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Errors & Outages","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Breached Metrics","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Breached Metrics","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Warnings","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Warnings","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"User Feedback","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"User Feedback","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Autofix","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Autofix","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Recently Run","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Recently Run","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"All Views","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All Views","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Configure","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Alerts Moved","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Alerts","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Moved","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Issues","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1EED","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ask Seer","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Seer","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Give Feedback","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View events","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
5558385063363686384
|
-2358471107926836827
|
click
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Unnamed Group
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Collapse
Listen
Show more options
Show thinking
Gemini said
Gemini said
Overview
Overview
This diff refactors the
LoadDocumentsAction
class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.
Architectural & Structural Changes
Architectural & Structural Changes
Dependency Injection:
Injected
EntityQueryBuilder
via the constructor instead of calling it statically.
Removed Traits & Constants:
Removed the
SkipActivityTrait
entirely (and its associated skip logic), as well as the
RDS_CHUNK_SIZE
constant.
Namespace Imports:
Added the
Throwable
import and removed
Illuminate\Support\Collection
.
Data Processing Refactor
Data Processing Refactor
Cursor Implementation:
Replaced
chunkByIdDesc
with
cursor()
, iterating through records sequentially rather than loading batches of 250 into memory.
Simplified Deletion Checks:
Replaced Laravel collection filtering (
whereNotNull('deleted_at')
) with a direct
$entityModel->isDeleted()
check on each model during iteration.
Removed Skip Logic:
Removed the
shouldSkipActivity
check, meaning all non-deleted models are now directly processed for updates.
Exception Handling:
Updated the catch block to use the imported
Throwable
interface rather than the fully qualified
\Throwable
.
Memory Optimization
Memory Optimization
Explicit Garbage Collection:
Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (
$entityModel->setRelations([])
) and unsetting the model (
unset($entityModel)
) explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.
You said
You are seasoned code reviewer and your task is to make detailed code
review of summarized page. First understand the code changes, then
evaluate it and try to find potential issues and bottlenecks.
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Code Review: LoadDocumentsAction Refactoring
Code Review:
LoadDocumentsAction
Refactoring
As requested, I have reviewed the refactoring of the
LoadDocumentsAction
class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.
Here is my detailed evaluation.
1. Strengths & Positive Changes
1. Strengths & Positive Changes
Dependency Injection:
Moving
EntityQueryBuilder
from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.
Simplified Readability:
Replacing the nested closures required by
chunkByIdDesc
with a flatter
foreach
structure makes the code easier to read and reason about.
Garbage Collection Awareness:
The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.
2. Critical Issues & Bottlenecks
2. Critical Issues & Bottlenecks
A. The "Infinite Accumulation" Memory Leak
A. The "Infinite Accumulation" Memory Leak
The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose.
The Issue:
The code iterates over the database cursor and manually unsets
$entityModel
to free memory. However, it simultaneously instantiates new
Document
objects and adds them to
$documentsToUpdate
(and IDs to
$documentsToDelete
).
The Bottleneck:
These collections are not flushed or processed within the loop; they are accumulated and returned at the end of the method. If this script processes 500,000 records,
$documentsToUpdate
will hold 500,000 ElasticSearch
Document
objects in RAM at once, inevitably leading to an Out Of Memory (OOM) fatal error.
B. Laravel cursor() and N+1 Query Problems
B. Laravel
cursor()
and N+1 Query Problems
Replacing
chunkByIdDesc()
with
cursor()
introduces a severe database performance risk.
The Issue:
Laravel's
cursor()
executes a single query and uses a PHP generator to yield results one by one via a PDO cursor. Because it does not process models in batches,
cursor()
cannot eager-load relationships.
*
The Bottleneck:
If
$entityModel->getIndexableAttributes()
relies on
any
database relationships (e.g., getting a user's company or tags), it will trigger an N+1 query. For 100,000 records, this will execute 100,001 database queries, absolutely hammering the database.
C. Long-Running PDO Connections
C. Long-Running PDO Connections
The Issue:
Because
cursor()
keeps a single database connection open while iterating through the results, any network latency encountered inside the loop extends the transaction time.
The Bottleneck:
If ElasticSearch
Document
instantiation or the Sentry API calls (on failure) take time, the PDO connection to the MariaDB database will remain open for an extended period, potentially leading to connection timeouts, blocked processes, or database lock exhaustion.
3. Minor Issues & Observations
3. Minor Issues & Observations
Missing Skip Logic:
The removal of
SkipActivityTrait
assumes these models no longer need to be bypassed. If this was an accidental omission, you will end up polluting ElasticSearch with activity logs that were previously filtered out, wasting ES storage and processing power.
Synchronous Sentry Calls:
If a specific batch of data is malformed and throws multiple
Throwable
errors consecutively,
Sentry::captureException
will make synchronous outbound HTTP calls for every failed record. This will severely degrade the throughput of the hydration process.
4. Recommendations for Refactoring
4. Recommendations for Refactoring
To resolve these issues, I recommend a hybrid approach utilizing Laravel's
lazyById()
(or returning to chunking) combined with batch-processing the ElasticSearch payloads:
Use
lazyById()
instead of
cursor()
:
* Laravel's
lazyById(250)
fetches records in chunks under the hood (allowing for eager loading of relations without N+1) but yields them as a flat generator to the
foreach
loop. This gives you the clean syntax of a generator with the safety of chunked eager loading.
Dispatch to ElasticSearch Inside the Loop:
* Do not wait until the end of the method to return massive collections.
Keep a counter. When
$documentsToUpdate
reaches a certain threshold (e.g., 500 documents), dispatch them to ElasticSearch, empty the
SimpleCollection
, and continue the loop.
Group Sentry Exceptions:
Consider implementing a circuit breaker or batching error logs so that a sudden spike in formatting errors doesn't result in thousands of synchronous API calls to Sentry.
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to main content
Skip to main content
Toggle organization menu
Issues
Issues
Explore
Explore
Dashboards
Dashboards
Monitors
Monitors
Settings
Settings
Try Business
What's New
Help
[EMAIL]
Issues
Expand
Feed
Feed
Errors & Outages
Errors & Outages
Breached Metrics
Breached Metrics
Warnings
Warnings
User Feedback
User Feedback
Autofix
Autofix
Recently Run
Recently Run
All Views
All Views
Configure
Alerts Moved
Alerts
Moved
Issues
Issues
View Project Details
APP-1EED
Ask Seer
Ask Seer
/
Give Feedback
SevenShores\Hubspot\Exceptions\BadRequest
View events...
|
10168
|
NULL
|
NULL
|
NULL
|
|
10169
|
466
|
7
|
2026-05-08T17:07:11.642047+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260031642_m2.jpg...
|
Firefox
|
SevenShores\Hubspot\Exceptions\BadRequest: Client SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT — Work...
|
1
|
jiminny.sentry.io/issues/7007366572/events/e72ac6c jiminny.sentry.io/issues/7007366572/events/e72ac6ccaa9445e3ae04d55cb8c32844/?project=82419...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Unnamed Group
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Collapse
Listen
Show more options
Show thinking
Gemini said
Gemini said
Overview
Overview
This diff refactors the
LoadDocumentsAction
class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.
Architectural & Structural Changes
Architectural & Structural Changes
Dependency Injection:
Injected
EntityQueryBuilder
via the constructor instead of calling it statically.
Removed Traits & Constants:
Removed the
SkipActivityTrait
entirely (and its associated skip logic), as well as the
RDS_CHUNK_SIZE
constant.
Namespace Imports:
Added the
Throwable
import and removed
Illuminate\Support\Collection
.
Data Processing Refactor
Data Processing Refactor
Cursor Implementation:
Replaced
chunkByIdDesc
with
cursor()
, iterating through records sequentially rather than loading batches of 250 into memory.
Simplified Deletion Checks:
Replaced Laravel collection filtering (
whereNotNull('deleted_at')
) with a direct
$entityModel->isDeleted()
check on each model during iteration.
Removed Skip Logic:
Removed the
shouldSkipActivity
check, meaning all non-deleted models are now directly processed for updates.
Exception Handling:
Updated the catch block to use the imported
Throwable
interface rather than the fully qualified
\Throwable
.
Memory Optimization
Memory Optimization
Explicit Garbage Collection:
Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (
$entityModel->setRelations([])
) and unsetting the model (
unset($entityModel)
) explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.
You said
You are seasoned code reviewer and your task is to make detailed code
review of summarized page. First understand the code changes, then
evaluate it and try to find potential issues and bottlenecks.
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Code Review: LoadDocumentsAction Refactoring
Code Review:
LoadDocumentsAction
Refactoring
As requested, I have reviewed the refactoring of the
LoadDocumentsAction
class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.
Here is my detailed evaluation.
1. Strengths & Positive Changes
1. Strengths & Positive Changes
Dependency Injection:
Moving
EntityQueryBuilder
from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.
Simplified Readability:
Replacing the nested closures required by
chunkByIdDesc
with a flatter
foreach
structure makes the code easier to read and reason about.
Garbage Collection Awareness:
The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.
2. Critical Issues & Bottlenecks
2. Critical Issues & Bottlenecks
A. The "Infinite Accumulation" Memory Leak
A. The "Infinite Accumulation" Memory Leak
The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose.
The Issue:
The code iterates over the database cursor and manually unsets
$entityModel
to free memory. However, it simultaneously instantiates new
Document
objects and adds them to
$documentsToUpdate
(and IDs to
$documentsToDelete
).
The Bottleneck:
These collections are not flushed or processed within the loop; they are accumulated and returned at the end of the method. If this script processes 500,000 records,
$documentsToUpdate
will hold 500,000 ElasticSearch
Document
objects in RAM at once, inevitably leading to an Out Of Memory (OOM) fatal error.
B. Laravel cursor() and N+1 Query Problems
B. Laravel
cursor()
and N+1 Query Problems
Replacing
chunkByIdDesc()
with
cursor()
introduces a severe database performance risk.
The Issue:
Laravel's
cursor()
executes a single query and uses a PHP generator to yield results one by one via a PDO cursor. Because it does not process models in batches,
cursor()
cannot eager-load relationships.
*
The Bottleneck:
If
$entityModel->getIndexableAttributes()
relies on
any
database relationships (e.g., getting a user's company or tags), it will trigger an N+1 query. For 100,000 records, this will execute 100,001 database queries, absolutely hammering the database.
C. Long-Running PDO Connections
C. Long-Running PDO Connections
The Issue:
Because
cursor()
keeps a single database connection open while iterating through the results, any network latency encountered inside the loop extends the transaction time.
The Bottleneck:
If ElasticSearch
Document
instantiation or the Sentry API calls (on failure) take time, the PDO connection to the MariaDB database will remain open for an extended period, potentially leading to connection timeouts, blocked processes, or database lock exhaustion.
3. Minor Issues & Observations
3. Minor Issues & Observations
Missing Skip Logic:
The removal of
SkipActivityTrait
assumes these models no longer need to be bypassed. If this was an accidental omission, you will end up polluting ElasticSearch with activity logs that were previously filtered out, wasting ES storage and processing power.
Synchronous Sentry Calls:
If a specific batch of data is malformed and throws multiple
Throwable
errors consecutively,
Sentry::captureException
will make synchronous outbound HTTP calls for every failed record. This will severely degrade the throughput of the hydration process.
4. Recommendations for Refactoring
4. Recommendations for Refactoring
To resolve these issues, I recommend a hybrid approach utilizing Laravel's
lazyById()
(or returning to chunking) combined with batch-processing the ElasticSearch payloads:
Use
lazyById()
instead of
cursor()
:
* Laravel's
lazyById(250)
fetches records in chunks under the hood (allowing for eager loading of relations without N+1) but yields them as a flat generator to the
foreach
loop. This gives you the clean syntax of a generator with the safety of chunked eager loading.
Dispatch to ElasticSearch Inside the Loop:
* Do not wait until the end of the method to return massive collections.
Keep a counter. When
$documentsToUpdate
reaches a certain threshold (e.g., 500 documents), dispatch them to ElasticSearch, empty the
SimpleCollection
, and continue the loop.
Group Sentry Exceptions:
Consider implementing a circuit breaker or batching error logs so that a sudden spike in formatting errors doesn't result in thousands of synchronous API calls to Sentry.
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to main content
Skip to main content
Toggle organization menu
Issues
Issues
Explore
Explore
Dashboards
Dashboards
Monitors
Monitors
Settings
Settings
Try Business
What's New
Help
[EMAIL]
Issues
Expand
Feed
Feed
Errors & Outages
Errors & Outages
Breached Metrics
Breached Metrics
Warnings
Warnings
User Feedback
User Feedback
Autofix
Autofix
Recently Run
Recently Run
All Views
All Views
Configure
Alerts Moved
Alerts
Moved
Issues
Issues
View Project Details
APP-1EED
Ask Seer
Ask Seer
/
Give Feedback
SevenShores\Hubspot\Exceptions\BadRequest
View events
Events (total)
Users (90d)
Level: Error
Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT","correlationId":"019e04ea-a (truncated...)
17K
0
Ongoing
/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php in Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService::executeSearchRequest
Resolve
Resolve
More resolve options
Archive
Archive
Archive options
Subscribe
Share
More Actions
Priority
Modify issue priority
High
Assignee
Modify issue assignee
Lukas Kovalik
All Envs
All Envs
90D
90D
Add a search term
Add a search term
Close sidebar
Toggle graph series - Events
Events
17K
Toggle graph series - Users
Users
0
release 68% 874599
release
68%
874599
environment 92% production
environment
92%
production
runtime.name 100% php
runtime.name
100%
php
os.build 92% #1 SMP Tue Jun 17 10:29:19 UTC 2025...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.2237367,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.23703457,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unnamed Group","depth":4,"bounds":{"left":0.2265625,"top":0.08978452,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"bounds":{"left":0.2265625,"top":0.11332801,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"bounds":{"left":0.23969415,"top":0.1245012,"width":0.4644282,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"bounds":{"left":0.2265625,"top":0.14604948,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"bounds":{"left":0.23969415,"top":0.15722266,"width":0.4644282,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.29105717,"top":0.15323225,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"bounds":{"left":0.2237367,"top":0.17877094,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"bounds":{"left":0.23703457,"top":0.18994413,"width":0.10721409,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.21149242,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.22266561,"width":0.17037898,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Feed — jiminny — Sentry","depth":4,"bounds":{"left":0.2237367,"top":0.2442139,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed — jiminny — Sentry","depth":5,"bounds":{"left":0.23703457,"top":0.25538707,"width":0.042719416,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.27693537,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.28810853,"width":0.18899602,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"bounds":{"left":0.2237367,"top":0.30965683,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"bounds":{"left":0.23703457,"top":0.32083002,"width":0.07164229,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.3423783,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.35355148,"width":0.19331782,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Problem loading page","depth":4,"bounds":{"left":0.2237367,"top":0.37509975,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Problem loading page","depth":5,"bounds":{"left":0.23703457,"top":0.38627294,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"bounds":{"left":0.2237367,"top":0.40782124,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"bounds":{"left":0.23703457,"top":0.41899443,"width":0.05651596,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.2237367,"top":0.4405427,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.23703457,"top":0.4517159,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.2237367,"top":0.47326416,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.23703457,"top":0.48443735,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.2237367,"top":0.5059856,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.23703457,"top":0.5171588,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI Features | Datadog","depth":4,"bounds":{"left":0.2237367,"top":0.5387071,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI Features | Datadog","depth":5,"bounds":{"left":0.23703457,"top":0.54988027,"width":0.037400264,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.5714286,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.5826017,"width":0.17037898,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.60415006,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.61532325,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.6368715,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.6480447,"width":0.16888298,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.2265625,"top":0.6711891,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.2265625,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.23753324,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.2486702,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.25980717,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.27094415,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.4084109,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.42037898,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.41771942,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.3073471,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.38979387,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.40309176,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.30302528,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.30302528,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\\Component\\ES\\Processor\\Actions;5namespace Jiminny\\Component\\ES\\Processor\\Actions;667use Elastica\\Document;7use Elastica\\Document;8-use Illuminate\\Support\\Collection;9use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;8use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;10use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;9use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;11use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;10use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;12use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;11use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;13-use Jiminny\\Component\\ES\\Processor\\Traits\\SkipActivityTrait;14use Jiminny\\Exceptions\\SyncActivityException;12use Jiminny\\Exceptions\\SyncActivityException;15use Jiminny\\Models\\Model;13use Jiminny\\Models\\Model;16use Sentry\\Laravel\\Facade as Sentry;14use Sentry\\Laravel\\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\\Component\\ES\\Processor\\Actions;5namespace Jiminny\\Component\\ES\\Processor\\Actions;667use Elastica\\Document;7use Elastica\\Document;8-use Illuminate\\Support\\Collection;9use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;8use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;10use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;9use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;11use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;10use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;12use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;11use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;13-use Jiminny\\Component\\ES\\Processor\\Traits\\SkipActivityTrait;14use Jiminny\\Exceptions\\SyncActivityException;12use Jiminny\\Exceptions\\SyncActivityException;15use Jiminny\\Models\\Model;13use Jiminny\\Models\\Model;16use Sentry\\Laravel\\Facade as Sentry;14use Sentry\\Laravel\\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Overview","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Overview","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This diff refactors the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Architectural & Structural Changes","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Architectural & Structural Changes","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dependency Injection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Injected","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EntityQueryBuilder","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"via the constructor instead of calling it statically.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Traits & Constants:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SkipActivityTrait","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely (and its associated skip logic), as well as the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RDS_CHUNK_SIZE","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Namespace Imports:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"import and removed","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Illuminate\\Support\\Collection","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Data Processing Refactor","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Data Processing Refactor","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Cursor Implementation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", iterating through records sequentially rather than loading batches of 250 into memory.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Simplified Deletion Checks:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Laravel collection filtering (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"whereNotNull('deleted_at')","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") with a direct","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->isDeleted()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check on each model during iteration.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Skip Logic:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"shouldSkipActivity","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check, meaning all non-deleted models are now directly processed for updates.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Exception Handling:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the catch block to use the imported","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"interface rather than the fully qualified","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Memory Optimization","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Memory Optimization","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Explicit Garbage Collection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->setRelations([])","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and unsetting the model (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"unset($entityModel)","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You are seasoned code reviewer and your task is to make detailed code","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review of summarized page. First understand the code changes, then","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"evaluate it and try to find potential issues and bottlenecks.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Code Review: LoadDocumentsAction Refactoring","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Code Review:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactoring","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"As requested, I have reviewed the refactoring of the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is my detailed evaluation.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Strengths & Positive Changes","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Strengths & Positive Changes","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dependency Injection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Moving","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EntityQueryBuilder","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Simplified Readability:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replacing the nested closures required by","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with a flatter","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"structure makes the code easier to read and reason about.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Garbage Collection Awareness:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Critical Issues & Bottlenecks","depth":23,"bounds":{"left":0.31333113,"top":0.0,"width":0.11502659,"height":0.01915403},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Critical Issues & Bottlenecks","depth":24,"bounds":{"left":0.31333113,"top":0.0,"width":0.08045213,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"A. The \"Infinite Accumulation\" Memory Leak","depth":23,"bounds":{"left":0.31333113,"top":0.019553073,"width":0.11502659,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"A. The \"Infinite Accumulation\" Memory Leak","depth":24,"bounds":{"left":0.31333113,"top":0.021149242,"width":0.11419548,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose.","depth":24,"bounds":{"left":0.31333113,"top":0.047486033,"width":0.11153591,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"bounds":{"left":0.3259641,"top":0.118515566,"width":0.02642952,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The code iterates over the database cursor and manually unsets","depth":26,"bounds":{"left":0.3259641,"top":0.118515566,"width":0.09242021,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel","depth":27,"bounds":{"left":0.32795876,"top":0.16121309,"width":0.03357713,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to free memory. However, it simultaneously instantiates new","depth":26,"bounds":{"left":0.3259641,"top":0.16001596,"width":0.101894945,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Document","depth":27,"bounds":{"left":0.32795876,"top":0.20271349,"width":0.022273935,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"objects and adds them to","depth":26,"bounds":{"left":0.3522274,"top":0.20151636,"width":0.064494684,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToUpdate","depth":27,"bounds":{"left":0.32795876,"top":0.22346368,"width":0.050199468,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(and IDs to","depth":26,"bounds":{"left":0.3801529,"top":0.22226655,"width":0.029089095,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToDelete","depth":27,"bounds":{"left":0.32795876,"top":0.2442139,"width":0.050199468,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"bounds":{"left":0.3801529,"top":0.24301676,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"bounds":{"left":0.3259641,"top":0.2725459,"width":0.041223403,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"These collections are not flushed or processed within the loop; they are accumulated and returned at the end of the method. If this script processes 500,000 records,","depth":26,"bounds":{"left":0.3259641,"top":0.2725459,"width":0.1022274,"height":0.09936153},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToUpdate","depth":27,"bounds":{"left":0.32795876,"top":0.377494,"width":0.050199468,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"will hold 500,000 ElasticSearch","depth":26,"bounds":{"left":0.3259641,"top":0.37629688,"width":0.10006649,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Document","depth":27,"bounds":{"left":0.3622008,"top":0.3982442,"width":0.022273935,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"objects in RAM at once, inevitably leading to an Out Of Memory (OOM) fatal error.","depth":26,"bounds":{"left":0.3259641,"top":0.39704707,"width":0.09923537,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"B. Laravel cursor() and N+1 Query Problems","depth":23,"bounds":{"left":0.31333113,"top":0.4792498,"width":0.11502659,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"B. Laravel","depth":24,"bounds":{"left":0.31333113,"top":0.48084596,"width":0.027094414,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":25,"bounds":{"left":0.34242022,"top":0.48084596,"width":0.025598405,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and N+1 Query Problems","depth":24,"bounds":{"left":0.31333113,"top":0.48084596,"width":0.097240694,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replacing","depth":24,"bounds":{"left":0.31333113,"top":0.5263368,"width":0.024933511,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc()","depth":25,"bounds":{"left":0.3402593,"top":0.5275339,"width":0.041888297,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":24,"bounds":{"left":0.38414228,"top":0.5263368,"width":0.012965426,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":25,"bounds":{"left":0.3991024,"top":0.5275339,"width":0.022273935,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"introduces a severe database performance risk.","depth":24,"bounds":{"left":0.31333113,"top":0.5263368,"width":0.111369684,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"bounds":{"left":0.3259641,"top":0.59736633,"width":0.02642952,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Laravel's","depth":26,"bounds":{"left":0.35239363,"top":0.59736633,"width":0.024102394,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"bounds":{"left":0.3784907,"top":0.59856343,"width":0.022273935,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"executes a single query and uses a PHP generator to yield results one by one via a PDO cursor. Because it does not process models in batches,","depth":26,"bounds":{"left":0.3259641,"top":0.59736633,"width":0.10139628,"height":0.09936153},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"bounds":{"left":0.37466756,"top":0.6815643,"width":0.022273935,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cannot eager-load relationships.","depth":26,"bounds":{"left":0.3259641,"top":0.6803671,"width":0.09391622,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*","depth":26,"bounds":{"left":0.3912899,"top":0.70111734,"width":0.0051529254,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"bounds":{"left":0.3259641,"top":0.70111734,"width":0.08178192,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If","depth":26,"bounds":{"left":0.3558843,"top":0.7218675,"width":0.005984043,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->getIndexableAttributes()","depth":27,"bounds":{"left":0.3259641,"top":0.72306466,"width":0.07413564,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"relies on","depth":26,"bounds":{"left":0.3977726,"top":0.7426177,"width":0.023105053,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"any","depth":26,"bounds":{"left":0.3259641,"top":0.7633679,"width":0.008643617,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"database relationships (e.g., getting a user's company or tags), it will trigger an N+1 query. For 100,000 records, this will execute 100,001 database queries, absolutely hammering the database.","depth":26,"bounds":{"left":0.3259641,"top":0.7633679,"width":0.10239362,"height":0.09936153},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"C. Long-Running PDO Connections","depth":23,"bounds":{"left":0.31333113,"top":0.887071,"width":0.11502659,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"C. Long-Running PDO Connections","depth":24,"bounds":{"left":0.31333113,"top":0.8886672,"width":0.09059176,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"bounds":{"left":0.3259641,"top":0.915004,"width":0.02642952,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Because","depth":26,"bounds":{"left":0.35239363,"top":0.915004,"width":0.023603724,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"bounds":{"left":0.37799203,"top":0.9162011,"width":0.022273935,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"keeps a single database connection open while iterating through the results, any network latency encountered inside the loop extends the transaction time.","depth":26,"bounds":{"left":0.3259641,"top":0.915004,"width":0.101230055,"height":0.084995985},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"bounds":{"left":0.3259641,"top":1.0,"width":0.041223403,"height":-0.027533889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If ElasticSearch","depth":26,"bounds":{"left":0.3671875,"top":1.0,"width":0.040059842,"height":-0.027533889},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Document","depth":27,"bounds":{"left":0.32795876,"top":1.0,"width":0.022273935,"height":-0.049481273},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"instantiation or the Sentry API calls (on failure) take time, the PDO connection to the MariaDB database will remain open for an extended period, potentially leading to connection timeouts, blocked processes, or database lock exhaustion.","depth":26,"bounds":{"left":0.3259641,"top":1.0,"width":0.10239362,"height":-0.048284173},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Minor Issues & Observations","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Minor Issues & Observations","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Missing Skip Logic:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The removal of","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SkipActivityTrait","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"assumes these models no longer need to be bypassed. If this was an accidental omission, you will end up polluting ElasticSearch with activity logs that were previously filtered out, wasting ES storage and processing power.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Synchronous Sentry Calls:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If a specific batch of data is malformed and throws multiple","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"errors consecutively,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Sentry::captureException","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"will make synchronous outbound HTTP calls for every failed record. This will severely degrade the throughput of the hydration process.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. Recommendations for Refactoring","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4. Recommendations for Refactoring","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To resolve these issues, I recommend a hybrid approach utilizing Laravel's","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lazyById()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(or returning to chunking) combined with batch-processing the ElasticSearch payloads:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Use","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lazyById()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"instead of","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Laravel's","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lazyById(250)","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"fetches records in chunks under the hood (allowing for eager loading of relations without N+1) but yields them as a flat generator to the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"loop. This gives you the clean syntax of a generator with the safety of chunked eager loading.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dispatch to ElasticSearch Inside the Loop:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Do not wait until the end of the method to return massive collections.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Keep a counter. When","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToUpdate","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"reaches a certain threshold (e.g., 500 documents), dispatch them to ElasticSearch, empty the","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SimpleCollection","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and continue the loop.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Sentry Exceptions:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Consider implementing a circuit breaker or batching error logs so that a sudden spike in formatting errors doesn't result in thousands of synchronous API calls to Sentry.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":21,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":21,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Redo","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share & export","depth":20,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"bounds":{"left":0.31665558,"top":0.8216281,"width":0.10638298,"height":0.01915403},"on_screen":true,"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"bounds":{"left":0.32330453,"top":0.82202715,"width":0.069980055,"height":0.018355945},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"bounds":{"left":0.31565824,"top":0.8216281,"width":0.0066489363,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"bounds":{"left":0.31266624,"top":0.8575419,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"bounds":{"left":0.32862368,"top":0.8575419,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"bounds":{"left":0.3856383,"top":0.85514766,"width":0.026097074,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"bounds":{"left":0.39095744,"top":0.8639266,"width":0.007480053,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Microphone","depth":19,"bounds":{"left":0.41373006,"top":0.85514766,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send message","depth":19,"bounds":{"left":0.42004654,"top":0.85434955,"width":0.013962766,"height":0.033519555},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.","depth":17,"bounds":{"left":0.30884308,"top":0.90901834,"width":0.11951463,"height":0.025139665},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"bounds":{"left":0.39079124,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"bounds":{"left":0.39079124,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"bounds":{"left":0.30302528,"top":0.92098963,"width":0.043218084,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"bounds":{"left":0.30867687,"top":0.95730245,"width":0.053523935,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"bounds":{"left":0.31432846,"top":0.96249,"width":0.042220745,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to main content","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to main content","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle organization menu","depth":11,"bounds":{"left":0.4459774,"top":0.059856344,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Issues","depth":12,"bounds":{"left":0.44049203,"top":0.09736632,"width":0.021609042,"height":0.050678372},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":14,"bounds":{"left":0.44614363,"top":0.13048683,"width":0.010305851,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Explore","depth":12,"bounds":{"left":0.44049203,"top":0.14804469,"width":0.021609042,"height":0.050678372},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Explore","depth":14,"bounds":{"left":0.4453125,"top":0.1811652,"width":0.011968086,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dashboards","depth":12,"bounds":{"left":0.44049203,"top":0.19872306,"width":0.021609042,"height":0.05027933},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dashboards","depth":14,"bounds":{"left":0.44165558,"top":0.23184358,"width":0.019281914,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Monitors","depth":12,"bounds":{"left":0.44049203,"top":0.2490024,"width":0.021609042,"height":0.050678372},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Monitors","depth":14,"bounds":{"left":0.44431517,"top":0.2821229,"width":0.013962766,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"bounds":{"left":0.44049203,"top":0.29968077,"width":0.021609042,"height":0.050678372},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"bounds":{"left":0.44448137,"top":0.33280128,"width":0.013630319,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Try Business","depth":10,"bounds":{"left":0.4459774,"top":0.88667196,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"What's New","depth":10,"bounds":{"left":0.4459774,"top":0.9114126,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Help","depth":10,"bounds":{"left":0.4459774,"top":0.93615323,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"lukas.kovalik@jiminny.com","depth":10,"bounds":{"left":0.4459774,"top":0.9680766,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Issues","depth":13,"bounds":{"left":0.40259308,"top":0.066640064,"width":0.014461436,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"bounds":{"left":0.4481383,"top":0.061452515,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Feed","depth":15,"bounds":{"left":0.39926863,"top":0.10055866,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed","depth":17,"bounds":{"left":0.4035904,"top":0.10734238,"width":0.010638298,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Errors & Outages","depth":15,"bounds":{"left":0.39926863,"top":0.14046289,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Errors & Outages","depth":17,"bounds":{"left":0.4035904,"top":0.14724661,"width":0.03673537,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Breached Metrics","depth":15,"bounds":{"left":0.39926863,"top":0.16759777,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Breached Metrics","depth":17,"bounds":{"left":0.4035904,"top":0.17438148,"width":0.037898935,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Warnings","depth":15,"bounds":{"left":0.39926863,"top":0.19473264,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Warnings","depth":17,"bounds":{"left":0.4035904,"top":0.20151636,"width":0.019946808,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"User Feedback","depth":15,"bounds":{"left":0.39926863,"top":0.22186752,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"User Feedback","depth":17,"bounds":{"left":0.4035904,"top":0.22865124,"width":0.032081116,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Autofix","depth":13,"bounds":{"left":0.39926863,"top":0.26177174,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Autofix","depth":16,"bounds":{"left":0.40325797,"top":0.26855546,"width":0.016289894,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Recently Run","depth":15,"bounds":{"left":0.39926863,"top":0.28731045,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Recently Run","depth":17,"bounds":{"left":0.4035904,"top":0.29409418,"width":0.028922873,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"All Views","depth":15,"bounds":{"left":0.39926863,"top":0.3272147,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All Views","depth":17,"bounds":{"left":0.4035904,"top":0.3339984,"width":0.019281914,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Configure","depth":14,"bounds":{"left":0.40325797,"top":0.3735036,"width":0.021941489,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Alerts Moved","depth":15,"bounds":{"left":0.39926863,"top":0.39225858,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Alerts","depth":17,"bounds":{"left":0.4035904,"top":0.3990423,"width":0.012799202,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Moved","depth":17,"bounds":{"left":0.43999335,"top":0.39984038,"width":0.012466756,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Issues","depth":12,"bounds":{"left":0.46908244,"top":0.06464485,"width":0.013796543,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":14,"bounds":{"left":0.46908244,"top":0.066640064,"width":0.013796543,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"bounds":{"left":0.4895279,"top":0.06624102,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1EED","depth":16,"bounds":{"left":0.49750665,"top":0.066640064,"width":0.021941489,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ask Seer","depth":10,"bounds":{"left":0.9350067,"top":0.059856344,"width":0.04720745,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Seer","depth":13,"bounds":{"left":0.94630986,"top":0.0650439,"width":0.019614361,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":14,"bounds":{"left":0.97423536,"top":0.065442935,"width":0.0021609042,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Give Feedback","depth":11,"bounds":{"left":0.98420876,"top":0.059856344,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View events","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Events (total)","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Users (90d)","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Error","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT\",\"correlationId\":\"019e04ea-a (truncated...)","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17K","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ongoing","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php in Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService::executeSearchRequest","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Resolve","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Resolve","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More resolve options","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Archive","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Archive","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Archive options","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Subscribe","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More Actions","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Priority","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue priority","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"High","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assignee","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue assignee","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Lukas Kovalik","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"All Envs","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All Envs","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"90D","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"90D","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Add a search term","depth":16,"on_screen":false,"help_text":"","placeholder":"Filter events…","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXComboBox","text":"Add a search term","depth":16,"on_screen":false,"help_text":"","placeholder":"Filter events…","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close sidebar","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Toggle graph series - Events","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Events","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17K","depth":15,"bounds":{"left":0.47972074,"top":0.0,"width":0.008643617,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle graph series - Users","depth":12,"bounds":{"left":0.47340426,"top":0.0,"width":0.021276595,"height":0.035115723},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Users","depth":15,"bounds":{"left":0.47855717,"top":0.0,"width":0.010970744,"height":0.010774142},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":15,"bounds":{"left":0.4822141,"top":0.0,"width":0.0034906915,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"release 68% 874599","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"release","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"68%","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"874599","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"environment 92% production","depth":12,"bounds":{"left":0.767121,"top":0.0,"width":0.11702128,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"environment","depth":14,"bounds":{"left":0.7691157,"top":0.0,"width":0.024767287,"height":0.010774142},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"92%","depth":14,"bounds":{"left":0.8359375,"top":0.0,"width":0.007978723,"height":0.010774142},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"production","depth":14,"bounds":{"left":0.845246,"top":0.0,"width":0.020279255,"height":0.010774142},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"runtime.name 100% php","depth":12,"bounds":{"left":0.767121,"top":0.0,"width":0.11702128,"height":0.0131683955},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"runtime.name","depth":14,"bounds":{"left":0.7691157,"top":0.0,"width":0.027094414,"height":0.010774142},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"100%","depth":14,"bounds":{"left":0.8334442,"top":0.0,"width":0.010472074,"height":0.010774142},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"php","depth":14,"bounds":{"left":0.845246,"top":0.0,"width":0.0071476065,"height":0.010774142},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"os.build 92% #1 SMP Tue Jun 17 10:29:19 UTC 2025","depth":12,"bounds":{"left":0.767121,"top":0.0,"width":0.11702128,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-8642407141658598641
|
-2358471107926836859
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Unnamed Group
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Collapse
Listen
Show more options
Show thinking
Gemini said
Gemini said
Overview
Overview
This diff refactors the
LoadDocumentsAction
class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.
Architectural & Structural Changes
Architectural & Structural Changes
Dependency Injection:
Injected
EntityQueryBuilder
via the constructor instead of calling it statically.
Removed Traits & Constants:
Removed the
SkipActivityTrait
entirely (and its associated skip logic), as well as the
RDS_CHUNK_SIZE
constant.
Namespace Imports:
Added the
Throwable
import and removed
Illuminate\Support\Collection
.
Data Processing Refactor
Data Processing Refactor
Cursor Implementation:
Replaced
chunkByIdDesc
with
cursor()
, iterating through records sequentially rather than loading batches of 250 into memory.
Simplified Deletion Checks:
Replaced Laravel collection filtering (
whereNotNull('deleted_at')
) with a direct
$entityModel->isDeleted()
check on each model during iteration.
Removed Skip Logic:
Removed the
shouldSkipActivity
check, meaning all non-deleted models are now directly processed for updates.
Exception Handling:
Updated the catch block to use the imported
Throwable
interface rather than the fully qualified
\Throwable
.
Memory Optimization
Memory Optimization
Explicit Garbage Collection:
Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (
$entityModel->setRelations([])
) and unsetting the model (
unset($entityModel)
) explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.
You said
You are seasoned code reviewer and your task is to make detailed code
review of summarized page. First understand the code changes, then
evaluate it and try to find potential issues and bottlenecks.
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Code Review: LoadDocumentsAction Refactoring
Code Review:
LoadDocumentsAction
Refactoring
As requested, I have reviewed the refactoring of the
LoadDocumentsAction
class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.
Here is my detailed evaluation.
1. Strengths & Positive Changes
1. Strengths & Positive Changes
Dependency Injection:
Moving
EntityQueryBuilder
from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.
Simplified Readability:
Replacing the nested closures required by
chunkByIdDesc
with a flatter
foreach
structure makes the code easier to read and reason about.
Garbage Collection Awareness:
The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.
2. Critical Issues & Bottlenecks
2. Critical Issues & Bottlenecks
A. The "Infinite Accumulation" Memory Leak
A. The "Infinite Accumulation" Memory Leak
The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose.
The Issue:
The code iterates over the database cursor and manually unsets
$entityModel
to free memory. However, it simultaneously instantiates new
Document
objects and adds them to
$documentsToUpdate
(and IDs to
$documentsToDelete
).
The Bottleneck:
These collections are not flushed or processed within the loop; they are accumulated and returned at the end of the method. If this script processes 500,000 records,
$documentsToUpdate
will hold 500,000 ElasticSearch
Document
objects in RAM at once, inevitably leading to an Out Of Memory (OOM) fatal error.
B. Laravel cursor() and N+1 Query Problems
B. Laravel
cursor()
and N+1 Query Problems
Replacing
chunkByIdDesc()
with
cursor()
introduces a severe database performance risk.
The Issue:
Laravel's
cursor()
executes a single query and uses a PHP generator to yield results one by one via a PDO cursor. Because it does not process models in batches,
cursor()
cannot eager-load relationships.
*
The Bottleneck:
If
$entityModel->getIndexableAttributes()
relies on
any
database relationships (e.g., getting a user's company or tags), it will trigger an N+1 query. For 100,000 records, this will execute 100,001 database queries, absolutely hammering the database.
C. Long-Running PDO Connections
C. Long-Running PDO Connections
The Issue:
Because
cursor()
keeps a single database connection open while iterating through the results, any network latency encountered inside the loop extends the transaction time.
The Bottleneck:
If ElasticSearch
Document
instantiation or the Sentry API calls (on failure) take time, the PDO connection to the MariaDB database will remain open for an extended period, potentially leading to connection timeouts, blocked processes, or database lock exhaustion.
3. Minor Issues & Observations
3. Minor Issues & Observations
Missing Skip Logic:
The removal of
SkipActivityTrait
assumes these models no longer need to be bypassed. If this was an accidental omission, you will end up polluting ElasticSearch with activity logs that were previously filtered out, wasting ES storage and processing power.
Synchronous Sentry Calls:
If a specific batch of data is malformed and throws multiple
Throwable
errors consecutively,
Sentry::captureException
will make synchronous outbound HTTP calls for every failed record. This will severely degrade the throughput of the hydration process.
4. Recommendations for Refactoring
4. Recommendations for Refactoring
To resolve these issues, I recommend a hybrid approach utilizing Laravel's
lazyById()
(or returning to chunking) combined with batch-processing the ElasticSearch payloads:
Use
lazyById()
instead of
cursor()
:
* Laravel's
lazyById(250)
fetches records in chunks under the hood (allowing for eager loading of relations without N+1) but yields them as a flat generator to the
foreach
loop. This gives you the clean syntax of a generator with the safety of chunked eager loading.
Dispatch to ElasticSearch Inside the Loop:
* Do not wait until the end of the method to return massive collections.
Keep a counter. When
$documentsToUpdate
reaches a certain threshold (e.g., 500 documents), dispatch them to ElasticSearch, empty the
SimpleCollection
, and continue the loop.
Group Sentry Exceptions:
Consider implementing a circuit breaker or batching error logs so that a sudden spike in formatting errors doesn't result in thousands of synchronous API calls to Sentry.
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to main content
Skip to main content
Toggle organization menu
Issues
Issues
Explore
Explore
Dashboards
Dashboards
Monitors
Monitors
Settings
Settings
Try Business
What's New
Help
[EMAIL]
Issues
Expand
Feed
Feed
Errors & Outages
Errors & Outages
Breached Metrics
Breached Metrics
Warnings
Warnings
User Feedback
User Feedback
Autofix
Autofix
Recently Run
Recently Run
All Views
All Views
Configure
Alerts Moved
Alerts
Moved
Issues
Issues
View Project Details
APP-1EED
Ask Seer
Ask Seer
/
Give Feedback
SevenShores\Hubspot\Exceptions\BadRequest
View events
Events (total)
Users (90d)
Level: Error
Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT","correlationId":"019e04ea-a (truncated...)
17K
0
Ongoing
/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php in Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService::executeSearchRequest
Resolve
Resolve
More resolve options
Archive
Archive
Archive options
Subscribe
Share
More Actions
Priority
Modify issue priority
High
Assignee
Modify issue assignee
Lukas Kovalik
All Envs
All Envs
90D
90D
Add a search term
Add a search term
Close sidebar
Toggle graph series - Events
Events
17K
Toggle graph series - Users
Users
0
release 68% 874599
release
68%
874599
environment 92% production
environment
92%
production
runtime.name 100% php
runtime.name
100%
php
os.build 92% #1 SMP Tue Jun 17 10:29:19 UTC 2025...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10168
|
465
|
6
|
2026-05-08T17:07:09.300052+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260029300_m1.jpg...
|
Firefox
|
SevenShores\Hubspot\Exceptions\BadRequest: Client SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT — Work...
|
1
|
jiminny.sentry.io/issues/7007366572/events/e72ac6c jiminny.sentry.io/issues/7007366572/events/e72ac6ccaa9445e3ae04d55cb8c32844/?project=82419...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
jiminny.atlassian.net
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Close tab
Unnamed Group
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Collapse
Listen
Show more options
Show thinking
Gemini said
Gemini said
Overview
Overview
This diff refactors the
LoadDocumentsAction
class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.
Architectural & Structural Changes
Architectural & Structural Changes
Dependency Injection:
Injected
EntityQueryBuilder
via the constructor instead of calling it statically.
Removed Traits & Constants:
Removed the
SkipActivityTrait
entirely (and its associated skip logic), as well as the
RDS_CHUNK_SIZE
constant.
Namespace Imports:
Added the
Throwable
import and removed
Illuminate\Support\Collection
.
Data Processing Refactor
Data Processing Refactor
Cursor Implementation:
Replaced
chunkByIdDesc
with
cursor()
, iterating through records sequentially rather than loading batches of 250 into memory.
Simplified Deletion Checks:
Replaced Laravel collection filtering (
whereNotNull('deleted_at')
) with a direct
$entityModel->isDeleted()
check on each model during iteration.
Removed Skip Logic:
Removed the
shouldSkipActivity
check, meaning all non-deleted models are now directly processed for updates.
Exception Handling:
Updated the catch block to use the imported
Throwable
interface rather than the fully qualified
\Throwable
.
Memory Optimization
Memory Optimization
Explicit Garbage Collection:
Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (
$entityModel->setRelations([])
) and unsetting the model (
unset($entityModel)
) explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.
You said
You are seasoned code reviewer and your task is to make detailed code
review of summarized page. First understand the code changes, then
evaluate it and try to find potential issues and bottlenecks.
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Code Review: LoadDocumentsAction Refactoring
Code Review:
LoadDocumentsAction
Refactoring
As requested, I have reviewed the refactoring of the
LoadDocumentsAction
class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.
Here is my detailed evaluation.
1. Strengths & Positive Changes
1. Strengths & Positive Changes
Dependency Injection:
Moving
EntityQueryBuilder
from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.
Simplified Readability:
Replacing the nested closures required by
chunkByIdDesc
with a flatter
foreach
structure makes the code easier to read and reason about.
Garbage Collection Awareness:
The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.
2. Critical Issues & Bottlenecks
2. Critical Issues & Bottlenecks
A. The "Infinite Accumulation" Memory Leak
A. The "Infinite Accumulation" Memory Leak
The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose.
The Issue:
The code iterates over the database cursor and manually unsets
$entityModel
to free memory. However, it simultaneously instantiates new
Document
objects and adds them to
$documentsToUpdate
(and IDs to
$documentsToDelete
).
The Bottleneck:
These collections are not flushed or processed within the loop; they are accumulated and returned at the end of the method. If this script processes 500,000 records,
$documentsToUpdate
will hold 500,000 ElasticSearch
Document
objects in RAM at once, inevitably leading to an Out Of Memory (OOM) fatal error.
B. Laravel cursor() and N+1 Query Problems
B. Laravel
cursor()
and N+1 Query Problems
Replacing
chunkByIdDesc()
with
cursor()
introduces a severe database performance risk.
The Issue:
Laravel's
cursor()
executes a single query and uses a PHP generator to yield results one by one via a PDO cursor. Because it does not process models in batches,
cursor()
cannot eager-load relationships.
*
The Bottleneck:
If
$entityModel->getIndexableAttributes()
relies on
any
database relationships (e.g., getting a user's company or tags), it will trigger an N+1 query. For 100,000 records, this will execute 100,001 database queries, absolutely hammering the database.
C. Long-Running PDO Connections
C. Long-Running PDO Connections...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"jiminny.atlassian.net","depth":4,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Unnamed Group","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Feed — jiminny — Sentry","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed — jiminny — Sentry","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Problem loading page","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Problem loading page","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI Features | Datadog","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI Features | Datadog","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.0013888889,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\\Component\\ES\\Processor\\Actions;5namespace Jiminny\\Component\\ES\\Processor\\Actions;667use Elastica\\Document;7use Elastica\\Document;8-use Illuminate\\Support\\Collection;9use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;8use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;10use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;9use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;11use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;10use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;12use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;11use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;13-use Jiminny\\Component\\ES\\Processor\\Traits\\SkipActivityTrait;14use Jiminny\\Exceptions\\SyncActivityException;12use Jiminny\\Exceptions\\SyncActivityException;15use Jiminny\\Models\\Model;13use Jiminny\\Models\\Model;16use Sentry\\Laravel\\Facade as Sentry;14use Sentry\\Laravel\\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\\Component\\ES\\Processor\\Actions;5namespace Jiminny\\Component\\ES\\Processor\\Actions;667use Elastica\\Document;7use Elastica\\Document;8-use Illuminate\\Support\\Collection;9use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;8use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;10use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;9use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;11use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;10use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;12use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;11use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;13-use Jiminny\\Component\\ES\\Processor\\Traits\\SkipActivityTrait;14use Jiminny\\Exceptions\\SyncActivityException;12use Jiminny\\Exceptions\\SyncActivityException;15use Jiminny\\Models\\Model;13use Jiminny\\Models\\Model;16use Sentry\\Laravel\\Facade as Sentry;14use Sentry\\Laravel\\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Overview","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Overview","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This diff refactors the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Architectural & Structural Changes","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Architectural & Structural Changes","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dependency Injection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Injected","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EntityQueryBuilder","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"via the constructor instead of calling it statically.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Traits & Constants:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SkipActivityTrait","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely (and its associated skip logic), as well as the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RDS_CHUNK_SIZE","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Namespace Imports:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"import and removed","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Illuminate\\Support\\Collection","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Data Processing Refactor","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Data Processing Refactor","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Cursor Implementation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", iterating through records sequentially rather than loading batches of 250 into memory.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Simplified Deletion Checks:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Laravel collection filtering (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"whereNotNull('deleted_at')","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") with a direct","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->isDeleted()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check on each model during iteration.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Skip Logic:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"shouldSkipActivity","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check, meaning all non-deleted models are now directly processed for updates.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Exception Handling:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the catch block to use the imported","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"interface rather than the fully qualified","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Memory Optimization","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Memory Optimization","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Explicit Garbage Collection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->setRelations([])","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and unsetting the model (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"unset($entityModel)","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You are seasoned code reviewer and your task is to make detailed code","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review of summarized page. First understand the code changes, then","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"evaluate it and try to find potential issues and bottlenecks.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Code Review: LoadDocumentsAction Refactoring","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Code Review:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactoring","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"As requested, I have reviewed the refactoring of the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is my detailed evaluation.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Strengths & Positive Changes","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Strengths & Positive Changes","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dependency Injection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Moving","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EntityQueryBuilder","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Simplified Readability:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replacing the nested closures required by","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with a flatter","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"structure makes the code easier to read and reason about.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Garbage Collection Awareness:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Critical Issues & Bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Critical Issues & Bottlenecks","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"A. The \"Infinite Accumulation\" Memory Leak","depth":23,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"A. The \"Infinite Accumulation\" Memory Leak","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The code iterates over the database cursor and manually unsets","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to free memory. However, it simultaneously instantiates new","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Document","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"objects and adds them to","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToUpdate","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(and IDs to","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToDelete","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"These collections are not flushed or processed within the loop; they are accumulated and returned at the end of the method. If this script processes 500,000 records,","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$documentsToUpdate","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"will hold 500,000 ElasticSearch","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Document","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"objects in RAM at once, inevitably leading to an Out Of Memory (OOM) fatal error.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"B. Laravel cursor() and N+1 Query Problems","depth":23,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"B. Laravel","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and N+1 Query Problems","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replacing","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc()","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"introduces a severe database performance risk.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Laravel's","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"executes a single query and uses a PHP generator to yield results one by one via a PDO cursor. Because it does not process models in batches,","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cannot eager-load relationships.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->getIndexableAttributes()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"relies on","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"any","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"database relationships (e.g., getting a user's company or tags), it will trigger an N+1 query. For 100,000 records, this will execute 100,001 database queries, absolutely hammering the database.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"C. Long-Running PDO Connections","depth":23,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"C. Long-Running PDO Connections","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8983982296192694291
|
-70642497222889083
|
click
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
jiminny.atlassian.net
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Close tab
Unnamed Group
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Collapse
Listen
Show more options
Show thinking
Gemini said
Gemini said
Overview
Overview
This diff refactors the
LoadDocumentsAction
class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.
Architectural & Structural Changes
Architectural & Structural Changes
Dependency Injection:
Injected
EntityQueryBuilder
via the constructor instead of calling it statically.
Removed Traits & Constants:
Removed the
SkipActivityTrait
entirely (and its associated skip logic), as well as the
RDS_CHUNK_SIZE
constant.
Namespace Imports:
Added the
Throwable
import and removed
Illuminate\Support\Collection
.
Data Processing Refactor
Data Processing Refactor
Cursor Implementation:
Replaced
chunkByIdDesc
with
cursor()
, iterating through records sequentially rather than loading batches of 250 into memory.
Simplified Deletion Checks:
Replaced Laravel collection filtering (
whereNotNull('deleted_at')
) with a direct
$entityModel->isDeleted()
check on each model during iteration.
Removed Skip Logic:
Removed the
shouldSkipActivity
check, meaning all non-deleted models are now directly processed for updates.
Exception Handling:
Updated the catch block to use the imported
Throwable
interface rather than the fully qualified
\Throwable
.
Memory Optimization
Memory Optimization
Explicit Garbage Collection:
Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (
$entityModel->setRelations([])
) and unsetting the model (
unset($entityModel)
) explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.
You said
You are seasoned code reviewer and your task is to make detailed code
review of summarized page. First understand the code changes, then
evaluate it and try to find potential issues and bottlenecks.
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Code Review: LoadDocumentsAction Refactoring
Code Review:
LoadDocumentsAction
Refactoring
As requested, I have reviewed the refactoring of the
LoadDocumentsAction
class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.
Here is my detailed evaluation.
1. Strengths & Positive Changes
1. Strengths & Positive Changes
Dependency Injection:
Moving
EntityQueryBuilder
from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.
Simplified Readability:
Replacing the nested closures required by
chunkByIdDesc
with a flatter
foreach
structure makes the code easier to read and reason about.
Garbage Collection Awareness:
The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.
2. Critical Issues & Bottlenecks
2. Critical Issues & Bottlenecks
A. The "Infinite Accumulation" Memory Leak
A. The "Infinite Accumulation" Memory Leak
The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose.
The Issue:
The code iterates over the database cursor and manually unsets
$entityModel
to free memory. However, it simultaneously instantiates new
Document
objects and adds them to
$documentsToUpdate
(and IDs to
$documentsToDelete
).
The Bottleneck:
These collections are not flushed or processed within the loop; they are accumulated and returned at the end of the method. If this script processes 500,000 records,
$documentsToUpdate
will hold 500,000 ElasticSearch
Document
objects in RAM at once, inevitably leading to an Out Of Memory (OOM) fatal error.
B. Laravel cursor() and N+1 Query Problems
B. Laravel
cursor()
and N+1 Query Problems
Replacing
chunkByIdDesc()
with
cursor()
introduces a severe database performance risk.
The Issue:
Laravel's
cursor()
executes a single query and uses a PHP generator to yield results one by one via a PDO cursor. Because it does not process models in batches,
cursor()
cannot eager-load relationships.
*
The Bottleneck:
If
$entityModel->getIndexableAttributes()
relies on
any
database relationships (e.g., getting a user's company or tags), it will trigger an N+1 query. For 100,000 records, this will execute 100,001 database queries, absolutely hammering the database.
C. Long-Running PDO Connections
C. Long-Running PDO Connections...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10167
|
466
|
6
|
2026-05-08T17:07:09.160619+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260029160_m2.jpg...
|
Firefox
|
SevenShores\Hubspot\Exceptions\BadRequest: Client SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {"status":"error","message":"You have reached your secondly limit.","errorType":"RATE_LIMIT — Work...
|
1
|
jiminny.sentry.io/issues/7007366572/events/e72ac6c jiminny.sentry.io/issues/7007366572/events/e72ac6ccaa9445e3ae04d55cb8c32844/?project=82419...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Close tab
Unnamed Group
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Collapse
Listen
Show more options
Show thinking
Gemini said
Gemini said
Overview
Overview
This diff refactors the
LoadDocumentsAction
class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.
Architectural & Structural Changes
Architectural & Structural Changes
Dependency Injection:
Injected
EntityQueryBuilder
via the constructor instead of calling it statically.
Removed Traits & Constants:
Removed the
SkipActivityTrait
entirely (and its associated skip logic), as well as the
RDS_CHUNK_SIZE
constant.
Namespace Imports:
Added the
Throwable
import and removed
Illuminate\Support\Collection
.
Data Processing Refactor
Data Processing Refactor
Cursor Implementation:
Replaced
chunkByIdDesc
with
cursor()
, iterating through records sequentially rather than loading batches of 250 into memory.
Simplified Deletion Checks:
Replaced Laravel collection filtering (
whereNotNull('deleted_at')
) with a direct
$entityModel->isDeleted()
check on each model during iteration.
Removed Skip Logic:
Removed the
shouldSkipActivity
check, meaning all non-deleted models are now directly processed for updates.
Exception Handling:
Updated the catch block to use the imported
Throwable
interface rather than the fully qualified
\Throwable
.
Memory Optimization
Memory Optimization
Explicit Garbage Collection:
Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (
$entityModel->setRelations([])
) and unsetting the model (
unset($entityModel)
) explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.
You said
You are seasoned code reviewer and your task is to make detailed code
review of summarized page. First understand the code changes, then
evaluate it and try to find potential issues and bottlenecks.
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Code Review: LoadDocumentsAction Refactoring
Code Review:
LoadDocumentsAction
Refactoring
As requested, I have reviewed the refactoring of the
LoadDocumentsAction
class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.
Here is my detailed evaluation.
1. Strengths & Positive Changes
1. Strengths & Positive Changes
Dependency Injection:
Moving
EntityQueryBuilder
from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.
Simplified Readability:
Replacing the nested closures required by
chunkByIdDesc
with a flatter
foreach
structure makes the code easier to read and reason about.
Garbage Collection Awareness:
The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.
2. Critical Issues & Bottlenecks
2. Critical Issues & Bottlenecks
A. The "Infinite Accumulation" Memory Leak
A. The "Infinite Accumulation" Memory Leak
The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose....
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.2237367,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.23703457,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.29105717,"top":0.05905826,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Unnamed Group","depth":4,"bounds":{"left":0.2265625,"top":0.08978452,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"bounds":{"left":0.2265625,"top":0.11332801,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"bounds":{"left":0.23969415,"top":0.1245012,"width":0.4644282,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"bounds":{"left":0.2265625,"top":0.14604948,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"bounds":{"left":0.23969415,"top":0.15722266,"width":0.4644282,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.29105717,"top":0.15323225,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"bounds":{"left":0.2237367,"top":0.17877094,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"bounds":{"left":0.23703457,"top":0.18994413,"width":0.10721409,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.21149242,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.22266561,"width":0.17037898,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Feed — jiminny — Sentry","depth":4,"bounds":{"left":0.2237367,"top":0.2442139,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed — jiminny — Sentry","depth":5,"bounds":{"left":0.23703457,"top":0.25538707,"width":0.042719416,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.27693537,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.28810853,"width":0.18899602,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"bounds":{"left":0.2237367,"top":0.30965683,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"bounds":{"left":0.23703457,"top":0.32083002,"width":0.07164229,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.3423783,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.35355148,"width":0.19331782,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Problem loading page","depth":4,"bounds":{"left":0.2237367,"top":0.37509975,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Problem loading page","depth":5,"bounds":{"left":0.23703457,"top":0.38627294,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"bounds":{"left":0.2237367,"top":0.40782124,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"bounds":{"left":0.23703457,"top":0.41899443,"width":0.05651596,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.2237367,"top":0.4405427,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.23703457,"top":0.4517159,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.2237367,"top":0.47326416,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.23703457,"top":0.48443735,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.2237367,"top":0.5059856,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.23703457,"top":0.5171588,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI Features | Datadog","depth":4,"bounds":{"left":0.2237367,"top":0.5387071,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI Features | Datadog","depth":5,"bounds":{"left":0.23703457,"top":0.54988027,"width":0.037400264,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.5714286,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.5826017,"width":0.17037898,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.60415006,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.61532325,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.6368715,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.6480447,"width":0.16888298,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.2265625,"top":0.6711891,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.2265625,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.23753324,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.2486702,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.25980717,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.27094415,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.4084109,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.42037898,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.41771942,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.3073471,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.38979387,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.40309176,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.30302528,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.30302528,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\\Component\\ES\\Processor\\Actions;5namespace Jiminny\\Component\\ES\\Processor\\Actions;667use Elastica\\Document;7use Elastica\\Document;8-use Illuminate\\Support\\Collection;9use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;8use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;10use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;9use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;11use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;10use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;12use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;11use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;13-use Jiminny\\Component\\ES\\Processor\\Traits\\SkipActivityTrait;14use Jiminny\\Exceptions\\SyncActivityException;12use Jiminny\\Exceptions\\SyncActivityException;15use Jiminny\\Models\\Model;13use Jiminny\\Models\\Model;16use Sentry\\Laravel\\Facade as Sentry;14use Sentry\\Laravel\\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\\Component\\ES\\Processor\\Actions;5namespace Jiminny\\Component\\ES\\Processor\\Actions;667use Elastica\\Document;7use Elastica\\Document;8-use Illuminate\\Support\\Collection;9use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;8use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;10use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;9use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;11use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;10use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;12use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;11use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;13-use Jiminny\\Component\\ES\\Processor\\Traits\\SkipActivityTrait;14use Jiminny\\Exceptions\\SyncActivityException;12use Jiminny\\Exceptions\\SyncActivityException;15use Jiminny\\Models\\Model;13use Jiminny\\Models\\Model;16use Sentry\\Laravel\\Facade as Sentry;14use Sentry\\Laravel\\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Overview","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Overview","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This diff refactors the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Architectural & Structural Changes","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Architectural & Structural Changes","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dependency Injection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Injected","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EntityQueryBuilder","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"via the constructor instead of calling it statically.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Traits & Constants:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SkipActivityTrait","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely (and its associated skip logic), as well as the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RDS_CHUNK_SIZE","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Namespace Imports:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"import and removed","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Illuminate\\Support\\Collection","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Data Processing Refactor","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Data Processing Refactor","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Cursor Implementation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", iterating through records sequentially rather than loading batches of 250 into memory.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Simplified Deletion Checks:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Laravel collection filtering (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"whereNotNull('deleted_at')","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") with a direct","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->isDeleted()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check on each model during iteration.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Skip Logic:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"shouldSkipActivity","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check, meaning all non-deleted models are now directly processed for updates.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Exception Handling:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the catch block to use the imported","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"interface rather than the fully qualified","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Memory Optimization","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Memory Optimization","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Explicit Garbage Collection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->setRelations([])","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and unsetting the model (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"unset($entityModel)","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You are seasoned code reviewer and your task is to make detailed code","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review of summarized page. First understand the code changes, then","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"evaluate it and try to find potential issues and bottlenecks.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Code Review: LoadDocumentsAction Refactoring","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Code Review:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactoring","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"As requested, I have reviewed the refactoring of the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is my detailed evaluation.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Strengths & Positive Changes","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Strengths & Positive Changes","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dependency Injection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Moving","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EntityQueryBuilder","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Simplified Readability:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replacing the nested closures required by","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with a flatter","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"structure makes the code easier to read and reason about.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Garbage Collection Awareness:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Critical Issues & Bottlenecks","depth":23,"bounds":{"left":0.31333113,"top":0.0,"width":0.11502659,"height":0.01915403},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Critical Issues & Bottlenecks","depth":24,"bounds":{"left":0.31333113,"top":0.0,"width":0.08045213,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"A. The \"Infinite Accumulation\" Memory Leak","depth":23,"bounds":{"left":0.31333113,"top":0.019553073,"width":0.11502659,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"A. The \"Infinite Accumulation\" Memory Leak","depth":24,"bounds":{"left":0.31333113,"top":0.021149242,"width":0.11419548,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose.","depth":24,"bounds":{"left":0.31333113,"top":0.047486033,"width":0.11153591,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-2700482857487266604
|
-2376485498383519355
|
click
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Close tab
Unnamed Group
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Collapse
Listen
Show more options
Show thinking
Gemini said
Gemini said
Overview
Overview
This diff refactors the
LoadDocumentsAction
class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.
Architectural & Structural Changes
Architectural & Structural Changes
Dependency Injection:
Injected
EntityQueryBuilder
via the constructor instead of calling it statically.
Removed Traits & Constants:
Removed the
SkipActivityTrait
entirely (and its associated skip logic), as well as the
RDS_CHUNK_SIZE
constant.
Namespace Imports:
Added the
Throwable
import and removed
Illuminate\Support\Collection
.
Data Processing Refactor
Data Processing Refactor
Cursor Implementation:
Replaced
chunkByIdDesc
with
cursor()
, iterating through records sequentially rather than loading batches of 250 into memory.
Simplified Deletion Checks:
Replaced Laravel collection filtering (
whereNotNull('deleted_at')
) with a direct
$entityModel->isDeleted()
check on each model during iteration.
Removed Skip Logic:
Removed the
shouldSkipActivity
check, meaning all non-deleted models are now directly processed for updates.
Exception Handling:
Updated the catch block to use the imported
Throwable
interface rather than the fully qualified
\Throwable
.
Memory Optimization
Memory Optimization
Explicit Garbage Collection:
Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (
$entityModel->setRelations([])
) and unsetting the model (
unset($entityModel)
) explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.
You said
You are seasoned code reviewer and your task is to make detailed code
review of summarized page. First understand the code changes, then
evaluate it and try to find potential issues and bottlenecks.
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Code Review: LoadDocumentsAction Refactoring
Code Review:
LoadDocumentsAction
Refactoring
As requested, I have reviewed the refactoring of the
LoadDocumentsAction
class. While the intent to modernize the architecture and optimize memory is clear, there are several critical architectural flaws and potential bottlenecks in the new implementation that need to be addressed before this goes to production.
Here is my detailed evaluation.
1. Strengths & Positive Changes
1. Strengths & Positive Changes
Dependency Injection:
Moving
EntityQueryBuilder
from a static call to an injected dependency significantly improves the testability of the class. You can now easily mock the query builder in your unit tests.
Simplified Readability:
Replacing the nested closures required by
chunkByIdDesc
with a flatter
foreach
structure makes the code easier to read and reason about.
Garbage Collection Awareness:
The developer is actively thinking about heap memory and Garbage Collection (GC), which is crucial for background workers and hydration scripts.
2. Critical Issues & Bottlenecks
2. Critical Issues & Bottlenecks
A. The "Infinite Accumulation" Memory Leak
A. The "Infinite Accumulation" Memory Leak
The primary goal of this refactor was memory optimization, but the implementation defeats its own purpose....
|
10166
|
NULL
|
NULL
|
NULL
|
|
10166
|
466
|
5
|
2026-05-08T17:07:03.344378+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260023344_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormcodeCode diff reviewulauon and senury tate PhostormcodeCode diff reviewulauon and senury tate concems are real Dut predate unis change —1aopen separate tickets for them rather than expand this PR's scope."summarize the code review suggestionswitch cursor() to lazyByld(250) . It preserves the single-loop, generator-style code in thenew vesion wnlerestonne crover Datenee eazer loaelne avolelne ntiongetindexableAttributes() ) and releasing the DB connection between chunks (avoidinglong-held PDO connections during ES/Sentry calls).une orner uwo concers raised ov ue reviewer — unbounded accumulaonin$documentsToUpdate / $documentsToDelete,and synchronous Sentry calls on every failure-— are vala dut dre-care uis rr ana ve lone in sevarare uckers. not as blockers nereok lets fully understand chunkByldDesc(250), cursor and lazyByld(250). I amnot sure l am fully clear on the issue l want to understnad it before suggestingthe changeDissected three Laravel iteration methods and their memory. connection, and eager-loading implications >G00d instincr — ler's actualv understand what each one does at the souroo leve. becausethe difterences only make sense once vou see the queries that actually hit the database.cursoroUnder the hood, this runs one query and uses PDO's unbuftered mode to stream results. OnMvSOL MariaDB that means P00: :MYSOL ATTR USE BUFFERED QUERY = false. The drivertells the server "send me rows as I ask for them." and the server keeps the result set openserver-side until voll ve consumed it all or the connection drons)What you get:SELECT * FROM activities WHERE ... ORDER BY id:-- A this querv stavs "active" on the connection for the entire foreachlPHP memory: only the current row's hydrated r 1el is alive. Very low.DB connection: held open and busy for the entire iteration. You cannot run another query onWrite a message…Opus 4.7 Adaptive vPP-1EED17 hours ago JSONerronTrace: Trace TDJumo to: HiahliahtsStack Tracec379cb6a6f224dcab13f4f1ed38d504brace* Display venshores Hubspot Exceptions BadRequestzleHttp Exception Clientexceptionnt error: POSt httos://api.hubapi.com/crm/v3/0biects/contact/search& resulted in a 429 100 Manv Requests' response:atus":"error", "message":"You have reached your secondly limit.","errorType":"RATE_LIMIT", "correlationId":"019e04ea-a (truncated...)chanism generichandled trueshed in non-aoo:/vendor/quzzlehtto/auzzle/src/Excention/RequestExceotion.oho 11 in Guzzeltto, Excention Request Excention:createShow 11 more framesp/Services/Crm/Hubspot/Paqination/HubspotPaqinationService.php:163inJiminny/Services\Crm.\Hubspot\Paqination.HubspotPaqinationSenvice:.executeSearchRequesp/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php:51 in JiminnyServices\Crm\Hubspot\Pagination\HubspotPaginationService::getPaginatedDataGeneratorin Appp/Services/crm/Hubspot/client.php:94 in JiminnyServices\erm\Hubspot\Client::getPaginatedDataIn Appo//Services/Crm/Hubsoot/Service.oho:1212 in Jiminnv Services Crm Hubsoot|Service:Jiminnv Services Crm Hubsoot.closure)ed from:/vendor/larave//tramework/src/llluminate/Cache/Repositorv.oho:564inlluminateCache-Reoositorv.remembenp/Services/Crm/Hubspot/Service.ohp:1206 in Jiminny Services Crm Hubspot Service:matchByNamep/Services/Crm/CachedCrmServiceDecorator.php:167 in Jiminny\Services\Crm\CachedCrmServiceDecorator:matchByNamein Appp/Services/Crm/ermActivityService.php:227in Jiminny Services\Crm \CrmActivityService::hndCrmRecordsIn Appo/Services/Crm/CrmActivitvService.ohv:130inJiminnv|Services\Crm\CrmActivitvService-undateParticinantsCrmDatalp/Services/Crm/CrmActivityService.php:81 in Jiminny\Services\Crm\CrmActivityService::updateCrmDataIn Appp/Jobs/Crm/MatchActivityCrmData.oho:107 in Jiminny Jobs Crm MatchActivityCrmData:Jiminny Jobs Crm (closure)In Aoped from: /vendor/laravel/frarb/Jobs/Crm/MatchActivityCrmData.php:87 in Jiminny\Jobs\Crm\MatchActivityCrmData:handleIn Apped from:vendor/laravel/fraork/src/Illuminate/Container/BoundMethod.php:36 in Illuminate\Container\BoundMethod:Illuminate\Container\(closure)chow 14 more framesb/Queue/Worker/Worker.php:71 in Jiminny\Queue\Worker\Worker:processnd feam. Wuondor/lorouol/feomaworl/ora/llluminoto/Ououo/worbornhn.4ZGd.llluminotolOuouolWorbor.run70hShow 17 more frames_Copyasv100% 5rilo May 20:0/.0.@ Ask Seer * .Try out Seer nowv Issue TrackingGithub# JiraV ACCIVICYAdd a comment.8 Assignedoy LuKas Kovalik to themselves.Marked as Ongoino6 months agcFirst Seen6 months agov PeooleLK participatingSSJKIPIN viewedCimilar IectesMerged Issues...
|
NULL
|
-127714801674363589
|
NULL
|
visual_change
|
ocr
|
NULL
|
PhostormcodeCode diff reviewulauon and senury tate PhostormcodeCode diff reviewulauon and senury tate concems are real Dut predate unis change —1aopen separate tickets for them rather than expand this PR's scope."summarize the code review suggestionswitch cursor() to lazyByld(250) . It preserves the single-loop, generator-style code in thenew vesion wnlerestonne crover Datenee eazer loaelne avolelne ntiongetindexableAttributes() ) and releasing the DB connection between chunks (avoidinglong-held PDO connections during ES/Sentry calls).une orner uwo concers raised ov ue reviewer — unbounded accumulaonin$documentsToUpdate / $documentsToDelete,and synchronous Sentry calls on every failure-— are vala dut dre-care uis rr ana ve lone in sevarare uckers. not as blockers nereok lets fully understand chunkByldDesc(250), cursor and lazyByld(250). I amnot sure l am fully clear on the issue l want to understnad it before suggestingthe changeDissected three Laravel iteration methods and their memory. connection, and eager-loading implications >G00d instincr — ler's actualv understand what each one does at the souroo leve. becausethe difterences only make sense once vou see the queries that actually hit the database.cursoroUnder the hood, this runs one query and uses PDO's unbuftered mode to stream results. OnMvSOL MariaDB that means P00: :MYSOL ATTR USE BUFFERED QUERY = false. The drivertells the server "send me rows as I ask for them." and the server keeps the result set openserver-side until voll ve consumed it all or the connection drons)What you get:SELECT * FROM activities WHERE ... ORDER BY id:-- A this querv stavs "active" on the connection for the entire foreachlPHP memory: only the current row's hydrated r 1el is alive. Very low.DB connection: held open and busy for the entire iteration. You cannot run another query onWrite a message…Opus 4.7 Adaptive vPP-1EED17 hours ago JSONerronTrace: Trace TDJumo to: HiahliahtsStack Tracec379cb6a6f224dcab13f4f1ed38d504brace* Display venshores Hubspot Exceptions BadRequestzleHttp Exception Clientexceptionnt error: POSt httos://api.hubapi.com/crm/v3/0biects/contact/search& resulted in a 429 100 Manv Requests' response:atus":"error", "message":"You have reached your secondly limit.","errorType":"RATE_LIMIT", "correlationId":"019e04ea-a (truncated...)chanism generichandled trueshed in non-aoo:/vendor/quzzlehtto/auzzle/src/Excention/RequestExceotion.oho 11 in Guzzeltto, Excention Request Excention:createShow 11 more framesp/Services/Crm/Hubspot/Paqination/HubspotPaqinationService.php:163inJiminny/Services\Crm.\Hubspot\Paqination.HubspotPaqinationSenvice:.executeSearchRequesp/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php:51 in JiminnyServices\Crm\Hubspot\Pagination\HubspotPaginationService::getPaginatedDataGeneratorin Appp/Services/crm/Hubspot/client.php:94 in JiminnyServices\erm\Hubspot\Client::getPaginatedDataIn Appo//Services/Crm/Hubsoot/Service.oho:1212 in Jiminnv Services Crm Hubsoot|Service:Jiminnv Services Crm Hubsoot.closure)ed from:/vendor/larave//tramework/src/llluminate/Cache/Repositorv.oho:564inlluminateCache-Reoositorv.remembenp/Services/Crm/Hubspot/Service.ohp:1206 in Jiminny Services Crm Hubspot Service:matchByNamep/Services/Crm/CachedCrmServiceDecorator.php:167 in Jiminny\Services\Crm\CachedCrmServiceDecorator:matchByNamein Appp/Services/Crm/ermActivityService.php:227in Jiminny Services\Crm \CrmActivityService::hndCrmRecordsIn Appo/Services/Crm/CrmActivitvService.ohv:130inJiminnv|Services\Crm\CrmActivitvService-undateParticinantsCrmDatalp/Services/Crm/CrmActivityService.php:81 in Jiminny\Services\Crm\CrmActivityService::updateCrmDataIn Appp/Jobs/Crm/MatchActivityCrmData.oho:107 in Jiminny Jobs Crm MatchActivityCrmData:Jiminny Jobs Crm (closure)In Aoped from: /vendor/laravel/frarb/Jobs/Crm/MatchActivityCrmData.php:87 in Jiminny\Jobs\Crm\MatchActivityCrmData:handleIn Apped from:vendor/laravel/fraork/src/Illuminate/Container/BoundMethod.php:36 in Illuminate\Container\BoundMethod:Illuminate\Container\(closure)chow 14 more framesb/Queue/Worker/Worker.php:71 in Jiminny\Queue\Worker\Worker:processnd feam. Wuondor/lorouol/feomaworl/ora/llluminoto/Ououo/worbornhn.4ZGd.llluminotolOuouolWorbor.run70hShow 17 more frames_Copyasv100% 5rilo May 20:0/.0.@ Ask Seer * .Try out Seer nowv Issue TrackingGithub# JiraV ACCIVICYAdd a comment.8 Assignedoy LuKas Kovalik to themselves.Marked as Ongoino6 months agcFirst Seen6 months agov PeooleLK participatingSSJKIPIN viewedCimilar IectesMerged Issues...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10165
|
465
|
5
|
2026-05-08T17:06:59.667621+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260019667_m1.jpg...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Show Replace Field
Search History
doSearch
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/1
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Code changed:
Hide
Sync Changes
Hide This Notification
7
48
1
33
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Hubspot;
use Carbon\Carbon;
use Exception;
use Generator;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Cache;
use InvalidArgumentException;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\FetchRelatedActivityInterface;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SavePlaybackLinkToCrmInterface;
use Jiminny\Contracts\Services\Crm\SendSummaryToCrmInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Contracts\ActivityContract;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Participant;
use Jiminny\Models\Playbook;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\ParticipantRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Hubspot\Actions\SyncArchivedProfilesAction;
use Jiminny\Services\Crm\Hubspot\Fields\ValueNormalizer;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\OpportunitySyncTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncCrmEntitiesTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncFieldsTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\WriteCrmTrait;
use Jiminny\Services\Crm\MatchDomainByEmailInterface;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\ResolveCompanyNameByEmailTrait;
use Jiminny\Utils\PlaybackUrlBuilder;
use Sentry;
use SevenShores\Hubspot\Exceptions\BadRequest;
use Throwable;
use UnexpectedValueException;
/**
* @phpstan-type CrmFieldDefinition array{
* name: string,
* label: string,
* description: string,
* type: string,
* fieldType: string,
* hidden: bool,
* showCurrencySymbol: bool,
* options: array<array{
* id: string,
* label: string,
* value?: string,
* }
*/
class Service extends BaseService implements
HubspotInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
SendSummaryToCrmInterface,
MatchDomainByEmailInterface,
SavePlaybackLinkToCrmInterface,
RemoteEntityManipulationInterface,
FetchRelatedActivityInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use ResolveCompanyNameByEmailTrait;
use SyncCrmEntitiesTrait;
use WriteCrmTrait;
use SyncFieldsTrait;
use OpportunitySyncTrait;
private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;
private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';
private const int BATCH_UPDATE_LIMIT = 100;
private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';
private const int TEN_SECONDLY_ROLLING_LIMIT = 10;
private const string TYPE_NOTE = 'NOTE';
private const string TYPE_MEETING = 'MEETING';
private const string TYPE_CALL = 'CALL';
private const string API_URL = '[URL_WITH_CREDENTIALS] ClientInterface|Client
*/
protected $client;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected ProspectPhotoPathService $prospectPhotoPathService;
private SyncFieldAction $syncFieldAction;
private PayloadBuilder $payloadBuilder;
private SyncRelatedActivityManager $syncRelatedActivityManager;
private SyncArchivedProfilesAction $syncArchivedProfilesAction;
private WebhookSyncBatchProcessor $batchProcessor;
public function __construct(
Client $client,
SyncFieldAction $syncFieldAction,
PayloadBuilder $payloadBuilder,
ProspectPhotoPathService $prospectPhotoPathService,
SyncArchivedProfilesAction $syncArchivedProfilesAction,
WebhookSyncBatchProcessor $batchProcessor,
) {
parent::__construct();
$this->client = $client;
$this->syncFieldAction = $syncFieldAction;
$this->prospectPhotoPathService = $prospectPhotoPathService;
$this->payloadBuilder = $payloadBuilder;
$this->syncArchivedProfilesAction = $syncArchivedProfilesAction;
$this->batchProcessor = $batchProcessor;
$this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [
'client' => $this->client,
'payloadBuilder' => $this->payloadBuilder,
'logger' => $this->logger,
]);
$this->crmEntityRepository = app(CrmEntityRepository::class);
$this->dealFieldsService = app(DealFieldsService::class);
}
public function getDisplayName(): string
{
return 'HubSpot';
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);
}
public function getClient(): Client
{
/** @var Client */
return $this->client;
}
/**
* Convert raw field data into a format compatible with CRM APIs.
*
* @param bool $internal Direction of the conversion.
* True is pulling from CRM, false normalize before sending to CRM.
*/
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return ValueNormalizer::normalize(
fieldType: $fieldType,
fieldValue: $fieldValue,
isInbound: $internal,
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'activityType',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
/**
* @inheritdoc
*/
public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
// Outcome should always be provided calls/meetings.
$fieldData = [
[
'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',
'object_type' => Field::OBJECT_TASK,
],
];
foreach ($fieldData as $data) {
$field = $this->config->fields()->where($data)->first();
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
}
return $fields;
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function syncField(Field $field): void
{
switch ($field->object_type) {
case Field::OBJECT_ACCOUNT:
$crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_CONTACT:
$crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_OPPORTUNITY:
$crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_TASK:
$this->syncSingleTaskField($field);
return;
default:
return;
}
$this->syncFieldAction->execute($field, $crmField->toArray());
}
/**
* @param array<array{
* id:string,
* label:string,
* value?:string
* }> $options
*
* @throws CrmException
*
* @return FieldData[]
*
*/
public function importPicklistValues(
Field $field,
array $options = [['id' => '', 'label' => '', 'value' => '']],
): array {
if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {
// We already have the options, no need to fetch them again
return $this->importOptions($field, $options);
}
$options = [];
switch ($field->getObjectType()) {
case Field::OBJECT_ACCOUNT:
$options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());
break;
case Field::OBJECT_CONTACT:
$options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());
break;
case Field::OBJECT_OPPORTUNITY:
// Hubspot has different endpoint for stages
$options = $this->getClient()->fetchOpportunityFieldOptions($field);
break;
case Field::OBJECT_TASK:
if ($field->getCrmProviderId() === 'disposition') {
$options = $this->getClient()->fetchDispositionFieldOptions();
} elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {
$options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);
}
break;
default:
$this->logger->warning('Invalid object type', [
'object_type' => $field->getObjectType(),
'field_id' => $field->getId(),
]);
throw new CrmException('Invalid object type');
}
return $this->importOptions($field, $options);
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
$missingStage = null;
try {
// Use the HubSpot API client instead of the SDK crmPipelines() method
$endpoint = self::getDealsPipelinesEndpoint();
$pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);
$pipelines = $pipelinesResponse->data->results;
} catch (RequestException|BadRequest $exception) {
throw $exception;
}
foreach ($pipelines as $pipeline) {
$stages = [];
// We create a business process to contain the pipeline, and store all stages against it.
$p = ResponseNormalize::normalizePipeline($pipeline);
// Create/update business process for this pipeline
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => $p['active'],
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
// Create/update record type clone
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'is_selectable' => $p['active'],
'business_process_id' => $businessProcess->id ?? null,
]);
// Stages - fetch all existing stages upfront to avoid N+1 queries
$existingStages = $this->config->stages()
->withTrashed()
->where('type', Stage::TYPE_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
foreach ($p['stages'] as $dealStage) {
$s = ResponseNormalize::normalizeDealStage($dealStage);
/** @var ?Stage $existingStage */
$existingStage = $existingStages->get($s['id']);
// Restore soft-deleted stages that are now active in HubSpot
if ($existingStage?->trashed() && $s['active']) {
$existingStage->restore();
}
// Upsert stage (updates soft-deleted records without restoring them)
$stage = $this->config->stages()->withTrashed()->updateOrCreate([
'crm_provider_id' => $s['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($s['label'], 0, 50),
'label' => mb_strimwidth($s['label'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $s['displayOrder'],
'is_selectable' => $s['active'],
'probability' => $s['probability'] * 100,
]);
if ($missingStageName === $s['id']) {
$missingStage = $stage;
}
$stages[] = $stage->id;
}
$businessProcess->stages()->sync($stages);
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
try {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
/** @var array<int, array<string, mixed>> */
return Cache::remember(
key: $this->team->getId() . $name . $count . $offset,
ttl: 300,
callback: function () use ($name, $offset, $count): array {
$data = [];
// Use the new V3 API to find contacts based on additional fields.
foreach (['companies', 'contacts'] as $objectType) {
$payload = $this->generateNameSearchPayload($name, $offset, $count);
$type = $objectType === 'companies' ? 'account' : 'contact';
try {
$response = $this->client->search($objectType, $payload);
// Build mapped list.
foreach ($response['results'] as $object) {
$properties = $object['properties'];
$objectName = $this->buildContactName($properties);
$record = [
'crmId' => $object['id'],
// Pass crmUrl to the FE, needed for success message in the extension when you log activity.
'crmUrl' => $this->generateProviderUrl($object['id'], $type),
'name' => $objectName,
'prospectType' => $type,
'phoneNumbers' => [],
];
if ($type === 'account') {
$record['industry'] = $properties['industry'] ?? null;
} else {
$record['title'] = $properties['jobtitle'] ?? null;
$record['organization'] = $properties['company'] ?? null;
}
$countryCode = $this->buildContactCountry($properties);
$parsedNumber = $this->buildContactPhone($countryCode, $properties);
// Add phone number to record.
if (! empty($parsedNumber['phone'])) {
$record['phoneNumbers'][] = [
'number' => $parsedNumber['phone'],
'nationalFormat' => phone_national($countryCode, $parsedNumber['phone']),
'type' => 'phone',
];
}
// Add mobile phone number to record.
if (! empty($properties['mobilephone'])) {
$mobileNumber = phone_e164($countryCode, $properties['mobilephone']);
if ($mobileNumber !== null) {
$record['phoneNumbers'][] = [
'number' => $mobileNumber,
'nationalFormat' => phone_national($countryCode, $mobileNumber),
'type' => 'mobile',
];
}
}
$data[] = $record;
}
} catch (BadRequest $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->getUuid(),
'request' => $payload,
'reason' => $e->getMessage(),
]);
throw $e;
}
}
return $data;
},
);
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
if ($crmAccountId === null) {
return $data;
}
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
$closedStages = $this->getClosedDealStages();
$payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(
$this->config,
$crmAccountId,
$closedStages,
);
$results = $this->client->getPaginatedData($payload, 'deals');
foreach ($results['results'] as $object) {
$properties = $object['properties'];
$amount = null;
if (empty($properties['amount']) === false) {
$currency = $properties['deal_currency_code'] ?? $this->config->default_currency;
// Values can contain commas and any junk so strip them.
$value = (float) preg_replace('/[^\d.]/', '', $properties['amount']);
$amount = formatCurrency($value, $currency);
}
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
if ($businessProcess === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
} else {
$stage = $businessProcess
->stages()
->where('crm_provider_id', $properties['dealstage'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages(null, $properties['dealstage']);
}
}
$recordType = null;
if ($businessProcess) {
$recordType = $businessProcess->recordTypes()->first();
}
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$record = [
'crmId' => $object['id'],
'name' => $properties['dealname'] ?? 'Unknown Deal',
'value' => $amount,
'won' => $isWon,
'closed' => $isWon || $isLost,
'stage' => [
'id' => $stage?->getUuid() ?? '',
'name' => $stage?->getName() ?? '',
],
];
if ($recordType) {
$record += [
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
}
if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array
{
$data = [];
switch ($objectType) {
case 'contact':
$hsObject = 'contact';
break;
case 'account':
$hsObject = 'company';
break;
default:
// This is a hack to prioritise and override a contact/company with a deal.
if ($opportunityId) {
$hsObject = 'deal';
$objectId = $opportunityId;
} else {
throw new InvalidArgumentException('Object type not supported.');
}
}
$engagementTypes = ['meetings', 'tasks'];
foreach ($engagementTypes as $engagementType) {
$payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);
$this->logger->info('[HubSpot] CRM Search requested', [
'request' => $payload,
]);
$engagements = $this->client->getPaginatedData($payload, $engagementType);
foreach ($engagements['results'] as $engagement) {
if ($engagementType == 'meetings') {
$title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';
} elseif ($engagementType == 'tasks') {
$title = $engagement['properties']['hs_task_subject'];
} else {
$title = 'Scheduled meeting';
}
$data[] = [
'crmId' => $engagement['id'],
'subject' => $title,
'due' => $engagement['properties']['hs_timestamp'],
'type' => $engagement['properties']['hs_activity_type'] ?? null,
];
}
}
usort($data, function ($item1, $item2) {
return $item2['due'] <=> $item1['due'];
});
return $data;
}
/**
* Try to find CRM Objects using email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$contactProperties = [
'email',
'firstname',
'lastname',
'country',
'phone',
'mobilephone',
'jobtitle',
'hubspot_owner_id',
'associatedcompanyid',
'photo',
];
$contact = null;
$account = null;
try {
$hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);
if ($hsContact) {
$contact = $this->importContact($hsContact);
$account = $contact->account;
}
$data = $this->convertCrmData($contact, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
} catch (BadRequest $e) {
$this->logger->warning('[HubSpot] Search failed', [
'team_id' => $this->team->getId(),
'search_identifier' => $email,
'reason' => $e->getMessage(),
]);
}
return null;
}
public function getDomain(string $email): ?string
{
return $this->getDomainFromEmail($email);
}
/**
* Try to find CRM objects using domain name of the email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByDomain(string $domain, ?int $userId = null): ?array
{
$companyName = $domain;
// Try to find a company matching their email domain.
$companyProperties = [
'country',
'phone',
'name',
'hs_avatar_filemanager_key',
'industry',
'hubspot_owner_id',
'domain',
];
try {
$hsAccounts = $this->client
->getInstance()
->companies()
->searchByDomain($companyName, $companyProperties);
} catch (Throwable $e) {
$this->logger->info('[HubSpot] Search failed', [
'error' => $e->getMessage(),
'domain' => $domain,
]);
return null;
}
$account = null;
// If there are multiple accounts, don't guess, we'll ask later.
if (\count($hsAccounts->data->results) === 1) {
// Persist this remote object.
$account = $this->syncAccount($hsAccounts->data->results[0]->companyId);
}
$data = $this->convertCrmData(null, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
}
/**
* @return array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array
{
$countryCode = null;
if ($contact && $contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account && $account->country_code) {
$countryCode = $account->country_code;
}
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
// If there are multiple opportunities, don't guess, we'll ask later.
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
if (str_contains($phone, '**')) {
return null;
}
// trim all whitespaces if present so the lookup doesn't fail
$phone = str_replace(' ', '', $phone);
// Check if the user is internal.
if ($this->isPhoneNumberOfTeamMember($phone)) {
return null;
}
$response = $this->searchForPhoneNumber($phone);
if (empty($response)) {
return null;
}
// This would ideally importContact instead but the response type differs.
$contact = $this->findAndSyncContact($response['results'][0]['id']);
if (! $contact instanceof Contact) {
return null;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
try {
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception $e) {
$this->logger->debug('[HubSpot] Opportunity failed to sync.', [
'reason' => $e->getMessage(),
]);
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
private function isPhoneNumberOfTeamMember(string $phone): bool
{
$teamRepository = app(TeamRepository::class);
$user = $teamRepository->findTeamMemberByPhone($this->team, $phone);
if ($user instanceof User) {
return true;
}
return false;
}
private function findAndSyncContact(string $crmId): ?Contact
{
try {
return $this->syncContact($crmId);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'reason' => $exception->getMessage(),
]);
return null;
}
}
private function hasResults(array $response): bool
{
return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;
}
private function searchForPhoneNumber(string $phone): array
{
// Normalizes the provided phone number for the API search.
$normalizedPhone = $this->normalizePhoneNumber($phone);
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);
$this->logger->info('[HubSpot] Phone match search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);
if (! $this->hasResults($response)) {
$nationalPhone = preg_replace('/\D/', '', phone_national(null, $phone));
$payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);
$this->logger->info('[HubSpot] Phone match national number search triggered', [
'phone' => $phone,
'nationalPhone' => $nationalPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
if (! $this->hasResults($response)) {
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);
$this->logger->info('[HubSpot] Phone match alternative search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
return $this->hasResults($response) ? $response : [];
}
private function handlePhoneSearchRequest(string $phone, array $payload): array
{
try {
return $this->client->search('contacts', $payload);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'phone' => $phone,
'reason' => $exception->getMessage(),
]);
return [];
}
}
private function normalizePhoneNumber(string $phone): string
{
return ltrim(phone_e164(null, $phone), '+0');
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$payload = $this->payloadBuilder->generateSearchContactsByNamePayload(
$name,
$this->getContactFields()
);
$hsContacts = $this->client->getPaginatedData($payload, 'contact');
if (empty($hsContacts['results'])) {
return false;
}
$contact = $this->importContact($hsContacts['results'][0]);
if ($contact === null) {
return false;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
});
return is_array($result) ? $result : null;
}
private function convertActivityAssociations(Activity $activity): array
{
return [
'contactIds' => $this->getParticipantsIds($activity),
'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],
'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],
'ownerIds' => [],
];
}
private function getParticipantsIds(Activity $activity): array
{
$attendees = [];
$participantRepository = app(ParticipantRepository::class);
$participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);
foreach ($participants as $participant) {
if ($participant->user_id || $participant->isCoach()) {
continue;
}
$contact = $participant->contact()->first();
if ($contact && $contact->crm_provider_id) {
$attendees[] = $contact->crm_provider_id;
} else {
if (! empty($participant->name)) {
$attendeeData = $this->fetchMissingAttendeeInfo($participant);
}
if (! empty($attendeeData['id'])) {
$attendees[] = $attendeeData['id'];
}
}
}
if ($activity->hasContact()) {
$attendees[] = $activity->contact->crm_provider_id;
}
return array_unique($attendees);
}
private function fetchMissingAttendeeInfo(Participant $participant): array
{
// Check if we need to look inside an account context.
$activity = $participant->getActivity();
$companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;
// First check the local data.
/** @var Contact[] $contacts */
$contacts = $this->team->contacts()
->with('account')
->where('name', $participant->name)
->whereNotNull('email')
->get();
foreach ($contacts as $contact) {
// If we have a company in scope, check the contact is associated to it.
if (
$companyId !== null
&& ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)
) {
continue;
}
return [
'id' => $contact->crm_provider_id,
'email' => $contact->email,
];
}
$payload = $this->generateNameSearchPayload($participant->name, 0, 20);
try {
$response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);
// TODO add some logic to choose the most suitable contact if multiple
foreach ($response['results'] as $object) {
$properties = $object['properties'];
if (empty($object['properties']) === false) {
// Check the company matches the contact.
// Todo: Move this check inside the API search.
if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {
continue;
}
return [
'id' => $object['id'],
'email' => $properties['email'],
];
}
}
} catch (Exception $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->id_string,
'request' => $payload,
'reason' => $e->getMessage(),
]);
}
return [];
}
/**
* Store transcripts as note engagement.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
// For HS no need to check if Crm profile - Log Notes field is enabled
// We only check if store_transcript toggle is enabled on crm profile.
$engagement = [
'active' => true,
'ownerId' => $this->profile->crm_provider_id,
'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,
'type' => 'NOTE',
];
// Generate activity transcription.
$transcriptionData = $this->generateTranscription($activity);
// Truncate Notes with max notes length because transcription text could be very long.
$transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);
$metadata = [
'body' => $transcripts,
];
$associations = $this->convertActivityAssociations($activity);
try {
$hsEngagement = $this->client
->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
$this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);
$noteId = $hsEngagement->data->engagement->id;
// Store crm logged id in transcription.
$transcription = $activity->getTranscription();
$transcription->crm_activity_id = $noteId;
$transcription->save();
} catch (Exception $e) {
Sentry::captureException($e);
}
}
/*
* @inheritdoc
*/
public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void
{
$payload = [
'properties' => $data,
];
try {
switch ($objectType) {
case FieldData::OBJECT_OPPORTUNITY:
$this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_CONTACT:
$this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_ACCOUNT:
$this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_TASK:
// Endpoint for Engagements not ready
$engagements = [
'type' => 'TASK',
];
$metadata = $data;
...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"on_screen":true,"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Replace Field","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Search History","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"doSearch","depth":4,"on_screen":true,"value":"doSearch","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Match Case","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Words","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Regex","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Replace History","depth":3,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Replace","depth":4,"on_screen":false,"role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Preserve case","depth":3,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1/1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Occurrence","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Occurrence","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Filter Search Results","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Window, Multiple Cursors","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Click to highlight","depth":4,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"7","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"48","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"33","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse Generator;\nuse GuzzleHttp\\Exception\\RequestException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse InvalidArgumentException;\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Contracts\\Services\\Crm\\ClientInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\FetchRelatedActivityInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\HubspotInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SavePlaybackLinkToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SendSummaryToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Contracts\\ActivityContract;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\Layout;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Participant;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\ParticipantRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Hubspot\\Actions\\SyncArchivedProfilesAction;\nuse Jiminny\\Services\\Crm\\Hubspot\\Fields\\ValueNormalizer;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\OpportunitySyncTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncCrmEntitiesTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncFieldsTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\WriteCrmTrait;\nuse Jiminny\\Services\\Crm\\MatchDomainByEmailInterface;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\ResolveCompanyNameByEmailTrait;\nuse Jiminny\\Utils\\PlaybackUrlBuilder;\nuse Sentry;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse Throwable;\nuse UnexpectedValueException;\n\n/**\n * @phpstan-type CrmFieldDefinition array{\n * name: string,\n * label: string,\n * description: string,\n * type: string,\n * fieldType: string,\n * hidden: bool,\n * showCurrencySymbol: bool,\n * options: array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }\n */\nclass Service extends BaseService implements\n HubspotInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n SendSummaryToCrmInterface,\n MatchDomainByEmailInterface,\n SavePlaybackLinkToCrmInterface,\n RemoteEntityManipulationInterface,\n FetchRelatedActivityInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use ResolveCompanyNameByEmailTrait;\n use SyncCrmEntitiesTrait;\n use WriteCrmTrait;\n use SyncFieldsTrait;\n use OpportunitySyncTrait;\n\n private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;\n\n private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';\n private const int BATCH_UPDATE_LIMIT = 100;\n private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';\n private const int TEN_SECONDLY_ROLLING_LIMIT = 10;\n\n private const string TYPE_NOTE = 'NOTE';\n\n private const string TYPE_MEETING = 'MEETING';\n\n private const string TYPE_CALL = 'CALL';\n\n private const string API_URL = 'https://api.hubapi.com';\n\n // NB: v1 is legacy - v3 is the newest\n private const string ENDPOINT_PIPELINES = '/crm-pipelines/v1/pipelines/';\n private const string PIPELINE_OBJECT_TYPE_DEALS = 'deals';\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n /**\n * @var ClientInterface|Client\n */\n protected $client;\n protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;\n protected CrmEntityRepository $crmEntityRepository;\n protected ProspectPhotoPathService $prospectPhotoPathService;\n\n private SyncFieldAction $syncFieldAction;\n private PayloadBuilder $payloadBuilder;\n private SyncRelatedActivityManager $syncRelatedActivityManager;\n private SyncArchivedProfilesAction $syncArchivedProfilesAction;\n private WebhookSyncBatchProcessor $batchProcessor;\n\n public function __construct(\n Client $client,\n SyncFieldAction $syncFieldAction,\n PayloadBuilder $payloadBuilder,\n ProspectPhotoPathService $prospectPhotoPathService,\n SyncArchivedProfilesAction $syncArchivedProfilesAction,\n WebhookSyncBatchProcessor $batchProcessor,\n ) {\n parent::__construct();\n\n $this->client = $client;\n $this->syncFieldAction = $syncFieldAction;\n $this->prospectPhotoPathService = $prospectPhotoPathService;\n $this->payloadBuilder = $payloadBuilder;\n $this->syncArchivedProfilesAction = $syncArchivedProfilesAction;\n $this->batchProcessor = $batchProcessor;\n $this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->client,\n ]);\n $this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [\n 'client' => $this->client,\n 'payloadBuilder' => $this->payloadBuilder,\n 'logger' => $this->logger,\n ]);\n $this->crmEntityRepository = app(CrmEntityRepository::class);\n $this->dealFieldsService = app(DealFieldsService::class);\n }\n\n public function getDisplayName(): string\n {\n return 'HubSpot';\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);\n }\n\n public function getClient(): Client\n {\n /** @var Client */\n return $this->client;\n }\n\n /**\n * Convert raw field data into a format compatible with CRM APIs.\n *\n * @param bool $internal Direction of the conversion.\n * True is pulling from CRM, false normalize before sending to CRM.\n */\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return ValueNormalizer::normalize(\n fieldType: $fieldType,\n fieldValue: $fieldValue,\n isInbound: $internal,\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n /** @var Field $activityField */\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'activityType',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n // Outcome should always be provided calls/meetings.\n $fieldData = [\n [\n 'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',\n 'object_type' => Field::OBJECT_TASK,\n ],\n ];\n\n foreach ($fieldData as $data) {\n $field = $this->config->fields()->where($data)->first();\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n }\n\n return $fields;\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldData = FieldDefinitions::followupFieldsFilter();\n\n foreach ($fieldData as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function syncField(Field $field): void\n {\n switch ($field->object_type) {\n case Field::OBJECT_ACCOUNT:\n $crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_CONTACT:\n $crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_OPPORTUNITY:\n $crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_TASK:\n $this->syncSingleTaskField($field);\n\n return;\n default:\n return;\n }\n\n $this->syncFieldAction->execute($field, $crmField->toArray());\n }\n\n /**\n * @param array<array{\n * id:string,\n * label:string,\n * value?:string\n * }> $options\n *\n * @throws CrmException\n *\n * @return FieldData[]\n *\n */\n public function importPicklistValues(\n Field $field,\n array $options = [['id' => '', 'label' => '', 'value' => '']],\n ): array {\n if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {\n // We already have the options, no need to fetch them again\n return $this->importOptions($field, $options);\n }\n\n $options = [];\n\n switch ($field->getObjectType()) {\n case Field::OBJECT_ACCOUNT:\n $options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_CONTACT:\n $options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_OPPORTUNITY:\n // Hubspot has different endpoint for stages\n $options = $this->getClient()->fetchOpportunityFieldOptions($field);\n\n break;\n\n case Field::OBJECT_TASK:\n if ($field->getCrmProviderId() === 'disposition') {\n $options = $this->getClient()->fetchDispositionFieldOptions();\n } elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {\n $options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);\n }\n\n break;\n\n default:\n $this->logger->warning('Invalid object type', [\n 'object_type' => $field->getObjectType(),\n 'field_id' => $field->getId(),\n ]);\n\n throw new CrmException('Invalid object type');\n }\n\n return $this->importOptions($field, $options);\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n $missingStage = null;\n\n try {\n // Use the HubSpot API client instead of the SDK crmPipelines() method\n $endpoint = self::getDealsPipelinesEndpoint();\n $pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);\n $pipelines = $pipelinesResponse->data->results;\n } catch (RequestException|BadRequest $exception) {\n throw $exception;\n }\n\n foreach ($pipelines as $pipeline) {\n $stages = [];\n\n // We create a business process to contain the pipeline, and store all stages against it.\n $p = ResponseNormalize::normalizePipeline($pipeline);\n\n // Create/update business process for this pipeline\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => $p['active'],\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n // Create/update record type clone\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'is_selectable' => $p['active'],\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n // Stages - fetch all existing stages upfront to avoid N+1 queries\n $existingStages = $this->config->stages()\n ->withTrashed()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get()\n ->keyBy('crm_provider_id');\n\n foreach ($p['stages'] as $dealStage) {\n $s = ResponseNormalize::normalizeDealStage($dealStage);\n\n /** @var ?Stage $existingStage */\n $existingStage = $existingStages->get($s['id']);\n\n // Restore soft-deleted stages that are now active in HubSpot\n if ($existingStage?->trashed() && $s['active']) {\n $existingStage->restore();\n }\n\n // Upsert stage (updates soft-deleted records without restoring them)\n $stage = $this->config->stages()->withTrashed()->updateOrCreate([\n 'crm_provider_id' => $s['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($s['label'], 0, 50),\n 'label' => mb_strimwidth($s['label'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $s['displayOrder'],\n 'is_selectable' => $s['active'],\n 'probability' => $s['probability'] * 100,\n ]);\n\n if ($missingStageName === $s['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage->id;\n }\n\n $businessProcess->stages()->sync($stages);\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n try {\n $endpoint = 'https://api.hubapi.com/integrations/v1/me';\n $response = $this->client->getInstance()->getClient()->request('get', $endpoint);\n\n $accountData = $response->data;\n $this->config->update(['default_currency' => $accountData->currency]);\n } catch (BadRequest $e) {\n throw new CrmException('Could not sync the organization.', $e->getCode(), $e);\n }\n }\n\n /**\n * @inheritdoc\n *\n * @throws CrmException\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $this->syncArchivedProfilesAction->execute($this->team, $this->client, $this->config);\n\n try {\n $owners = $this->client->getOwners();\n } catch (\\HubSpot\\Client\\Crm\\Owners\\ApiException $e) {\n $this->logger->error('[HubSpot] Could not sync the profiles.', [\n 'team_id' => $this->team->getId(),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new CrmException('Could not sync the profiles.', $e->getCode(), $e);\n }\n\n $profileRepository = app(ProfileRepository::class);\n $teamRepository = app(TeamRepository::class);\n\n foreach ($owners as $owner) {\n if ($owner->getArchived()) {\n // not supposed to fetch archived, but log anyway\n $this->logger->warning('[HubSpot] Found archived owner', [\n 'crm_provider_id' => $owner->getId(),\n 'email' => $owner->getEmail(),\n ]);\n\n continue;\n }\n\n $email = $owner->getEmail();\n if ($email === null) {\n continue;\n }\n\n $user = $teamRepository->findActiveTeamMemberByEmail($this->team, $email);\n\n if (! $user instanceof User) {\n continue;\n }\n\n $profile = $profileRepository->updateOrCreateProfile($user, [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $owner->getId(),\n ]);\n\n if ($userToSearch && $userToSearch->getId() === $user->getId()) {\n return $profile;\n }\n }\n\n return null;\n }\n\n private function generateNameSearchPayload(string $name, int $offset, int $limit): array\n {\n $payload = [\n 'query' => $name,\n 'sorts' => [\n [\n 'propertyName' => 'modifieddate',\n 'direction' => 'DESCENDING',\n ],\n ],\n 'properties' => [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n 'industry',\n 'name',\n 'company',\n ],\n 'limit' => $limit,\n 'after' => $offset,\n ];\n\n $this->logger->debug('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n return $payload;\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n /** @var array<int, array<string, mixed>> */\n return Cache::remember(\n key: $this->team->getId() . $name . $count . $offset,\n ttl: 300,\n callback: function () use ($name, $offset, $count): array {\n $data = [];\n\n // Use the new V3 API to find contacts based on additional fields.\n foreach (['companies', 'contacts'] as $objectType) {\n $payload = $this->generateNameSearchPayload($name, $offset, $count);\n $type = $objectType === 'companies' ? 'account' : 'contact';\n\n try {\n $response = $this->client->search($objectType, $payload);\n\n // Build mapped list.\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n\n $objectName = $this->buildContactName($properties);\n\n $record = [\n 'crmId' => $object['id'],\n // Pass crmUrl to the FE, needed for success message in the extension when you log activity.\n 'crmUrl' => $this->generateProviderUrl($object['id'], $type),\n 'name' => $objectName,\n 'prospectType' => $type,\n 'phoneNumbers' => [],\n ];\n\n if ($type === 'account') {\n $record['industry'] = $properties['industry'] ?? null;\n } else {\n $record['title'] = $properties['jobtitle'] ?? null;\n $record['organization'] = $properties['company'] ?? null;\n }\n\n $countryCode = $this->buildContactCountry($properties);\n $parsedNumber = $this->buildContactPhone($countryCode, $properties);\n\n // Add phone number to record.\n if (! empty($parsedNumber['phone'])) {\n $record['phoneNumbers'][] = [\n 'number' => $parsedNumber['phone'],\n 'nationalFormat' => phone_national($countryCode, $parsedNumber['phone']),\n 'type' => 'phone',\n ];\n }\n\n // Add mobile phone number to record.\n if (! empty($properties['mobilephone'])) {\n $mobileNumber = phone_e164($countryCode, $properties['mobilephone']);\n if ($mobileNumber !== null) {\n $record['phoneNumbers'][] = [\n 'number' => $mobileNumber,\n 'nationalFormat' => phone_national($countryCode, $mobileNumber),\n 'type' => 'mobile',\n ];\n }\n }\n\n $data[] = $record;\n }\n } catch (BadRequest $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->getUuid(),\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n }\n\n return $data;\n },\n );\n }\n\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n\n if ($crmAccountId === null) {\n return $data;\n }\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n $closedStages = $this->getClosedDealStages();\n $payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(\n $this->config,\n $crmAccountId,\n $closedStages,\n );\n\n $results = $this->client->getPaginatedData($payload, 'deals');\n\n foreach ($results['results'] as $object) {\n $properties = $object['properties'];\n\n $amount = null;\n if (empty($properties['amount']) === false) {\n $currency = $properties['deal_currency_code'] ?? $this->config->default_currency;\n\n // Values can contain commas and any junk so strip them.\n $value = (float) preg_replace('/[^\\d.]/', '', $properties['amount']);\n $amount = formatCurrency($value, $currency);\n }\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n } else {\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', $properties['dealstage'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages(null, $properties['dealstage']);\n }\n }\n\n $recordType = null;\n if ($businessProcess) {\n $recordType = $businessProcess->recordTypes()->first();\n }\n\n $isWon = in_array($properties['dealstage'], $closedStages['won']);\n $isLost = in_array($properties['dealstage'], $closedStages['lost']);\n\n $record = [\n 'crmId' => $object['id'],\n 'name' => $properties['dealname'] ?? 'Unknown Deal',\n 'value' => $amount,\n 'won' => $isWon,\n 'closed' => $isWon || $isLost,\n 'stage' => [\n 'id' => $stage?->getUuid() ?? '',\n 'name' => $stage?->getName() ?? '',\n ],\n ];\n\n if ($recordType) {\n $record += [\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n }\n\n if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = [];\n switch ($objectType) {\n case 'contact':\n $hsObject = 'contact';\n\n break;\n case 'account':\n $hsObject = 'company';\n\n break;\n default:\n // This is a hack to prioritise and override a contact/company with a deal.\n if ($opportunityId) {\n $hsObject = 'deal';\n $objectId = $opportunityId;\n } else {\n throw new InvalidArgumentException('Object type not supported.');\n }\n }\n\n $engagementTypes = ['meetings', 'tasks'];\n\n foreach ($engagementTypes as $engagementType) {\n $payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);\n\n $this->logger->info('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n $engagements = $this->client->getPaginatedData($payload, $engagementType);\n\n foreach ($engagements['results'] as $engagement) {\n if ($engagementType == 'meetings') {\n $title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';\n } elseif ($engagementType == 'tasks') {\n $title = $engagement['properties']['hs_task_subject'];\n } else {\n $title = 'Scheduled meeting';\n }\n\n $data[] = [\n 'crmId' => $engagement['id'],\n 'subject' => $title,\n 'due' => $engagement['properties']['hs_timestamp'],\n 'type' => $engagement['properties']['hs_activity_type'] ?? null,\n ];\n }\n }\n\n usort($data, function ($item1, $item2) {\n return $item2['due'] <=> $item1['due'];\n });\n\n return $data;\n }\n\n /**\n * Try to find CRM Objects using email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $contactProperties = [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n ];\n $contact = null;\n $account = null;\n\n try {\n $hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);\n\n if ($hsContact) {\n $contact = $this->importContact($hsContact);\n $account = $contact->account;\n }\n\n $data = $this->convertCrmData($contact, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n } catch (BadRequest $e) {\n $this->logger->warning('[HubSpot] Search failed', [\n 'team_id' => $this->team->getId(),\n 'search_identifier' => $email,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return null;\n }\n\n public function getDomain(string $email): ?string\n {\n return $this->getDomainFromEmail($email);\n }\n\n /**\n * Try to find CRM objects using domain name of the email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByDomain(string $domain, ?int $userId = null): ?array\n {\n $companyName = $domain;\n\n // Try to find a company matching their email domain.\n $companyProperties = [\n 'country',\n 'phone',\n 'name',\n 'hs_avatar_filemanager_key',\n 'industry',\n 'hubspot_owner_id',\n 'domain',\n ];\n\n try {\n $hsAccounts = $this->client\n ->getInstance()\n ->companies()\n ->searchByDomain($companyName, $companyProperties);\n } catch (Throwable $e) {\n $this->logger->info('[HubSpot] Search failed', [\n 'error' => $e->getMessage(),\n 'domain' => $domain,\n ]);\n\n return null;\n }\n\n $account = null;\n // If there are multiple accounts, don't guess, we'll ask later.\n if (\\count($hsAccounts->data->results) === 1) {\n // Persist this remote object.\n $account = $this->syncAccount($hsAccounts->data->results[0]->companyId);\n }\n\n $data = $this->convertCrmData(null, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array\n {\n $countryCode = null;\n if ($contact && $contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account && $account->country_code) {\n $countryCode = $account->country_code;\n }\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n // If there are multiple opportunities, don't guess, we'll ask later.\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n protected function getCacheKey(string $object, ?int $userId = null): ?string\n {\n $key = $this->team->getId() . $object;\n $keySuffix = $this->getOwnerKeySuffix($userId);\n\n return $key . $keySuffix;\n }\n\n private function getOwnerKeySuffix(?int $userId = null): string\n {\n return $userId === null ? '' : (string) $userId;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n if (str_contains($phone, '**')) {\n return null;\n }\n\n // trim all whitespaces if present so the lookup doesn't fail\n $phone = str_replace(' ', '', $phone);\n\n // Check if the user is internal.\n if ($this->isPhoneNumberOfTeamMember($phone)) {\n return null;\n }\n\n $response = $this->searchForPhoneNumber($phone);\n if (empty($response)) {\n return null;\n }\n\n // This would ideally importContact instead but the response type differs.\n $contact = $this->findAndSyncContact($response['results'][0]['id']);\n if (! $contact instanceof Contact) {\n return null;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n\n try {\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (Exception $e) {\n $this->logger->debug('[HubSpot] Opportunity failed to sync.', [\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n private function isPhoneNumberOfTeamMember(string $phone): bool\n {\n $teamRepository = app(TeamRepository::class);\n $user = $teamRepository->findTeamMemberByPhone($this->team, $phone);\n\n if ($user instanceof User) {\n return true;\n }\n\n return false;\n }\n\n private function findAndSyncContact(string $crmId): ?Contact\n {\n try {\n return $this->syncContact($crmId);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'reason' => $exception->getMessage(),\n ]);\n\n return null;\n }\n }\n\n private function hasResults(array $response): bool\n {\n return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;\n }\n\n private function searchForPhoneNumber(string $phone): array\n {\n // Normalizes the provided phone number for the API search.\n $normalizedPhone = $this->normalizePhoneNumber($phone);\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);\n\n $this->logger->info('[HubSpot] Phone match search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);\n\n if (! $this->hasResults($response)) {\n $nationalPhone = preg_replace('/\\D/', '', phone_national(null, $phone));\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);\n\n $this->logger->info('[HubSpot] Phone match national number search triggered', [\n 'phone' => $phone,\n 'nationalPhone' => $nationalPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n if (! $this->hasResults($response)) {\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);\n\n $this->logger->info('[HubSpot] Phone match alternative search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n return $this->hasResults($response) ? $response : [];\n }\n\n private function handlePhoneSearchRequest(string $phone, array $payload): array\n {\n try {\n return $this->client->search('contacts', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'phone' => $phone,\n 'reason' => $exception->getMessage(),\n ]);\n\n return [];\n }\n }\n\n private function normalizePhoneNumber(string $phone): string\n {\n return ltrim(phone_e164(null, $phone), '+0');\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $cacheKey = $this->getCacheKey($name, $userId);\n\n $result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {\n $payload = $this->payloadBuilder->generateSearchContactsByNamePayload(\n $name,\n $this->getContactFields()\n );\n\n $hsContacts = $this->client->getPaginatedData($payload, 'contact');\n if (empty($hsContacts['results'])) {\n return false;\n }\n\n $contact = $this->importContact($hsContacts['results'][0]);\n if ($contact === null) {\n return false;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n });\n\n return is_array($result) ? $result : null;\n }\n\n\n private function convertActivityAssociations(Activity $activity): array\n {\n return [\n 'contactIds' => $this->getParticipantsIds($activity),\n 'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],\n 'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],\n 'ownerIds' => [],\n ];\n }\n\n private function getParticipantsIds(Activity $activity): array\n {\n $attendees = [];\n\n $participantRepository = app(ParticipantRepository::class);\n $participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);\n foreach ($participants as $participant) {\n if ($participant->user_id || $participant->isCoach()) {\n continue;\n }\n\n $contact = $participant->contact()->first();\n if ($contact && $contact->crm_provider_id) {\n $attendees[] = $contact->crm_provider_id;\n } else {\n if (! empty($participant->name)) {\n $attendeeData = $this->fetchMissingAttendeeInfo($participant);\n }\n if (! empty($attendeeData['id'])) {\n $attendees[] = $attendeeData['id'];\n }\n }\n }\n\n if ($activity->hasContact()) {\n $attendees[] = $activity->contact->crm_provider_id;\n }\n\n return array_unique($attendees);\n }\n\n private function fetchMissingAttendeeInfo(Participant $participant): array\n {\n // Check if we need to look inside an account context.\n $activity = $participant->getActivity();\n $companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;\n\n // First check the local data.\n /** @var Contact[] $contacts */\n $contacts = $this->team->contacts()\n ->with('account')\n ->where('name', $participant->name)\n ->whereNotNull('email')\n ->get();\n\n foreach ($contacts as $contact) {\n // If we have a company in scope, check the contact is associated to it.\n if (\n $companyId !== null\n && ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)\n ) {\n continue;\n }\n\n return [\n 'id' => $contact->crm_provider_id,\n 'email' => $contact->email,\n ];\n }\n\n $payload = $this->generateNameSearchPayload($participant->name, 0, 20);\n\n try {\n $response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);\n\n // TODO add some logic to choose the most suitable contact if multiple\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n if (empty($object['properties']) === false) {\n // Check the company matches the contact.\n // Todo: Move this check inside the API search.\n if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {\n continue;\n }\n\n return [\n 'id' => $object['id'],\n 'email' => $properties['email'],\n ];\n }\n }\n } catch (Exception $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->id_string,\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [];\n }\n\n /**\n * Store transcripts as note engagement.\n *\n * @throws Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // For HS no need to check if Crm profile - Log Notes field is enabled\n // We only check if store_transcript toggle is enabled on crm profile.\n $engagement = [\n 'active' => true,\n 'ownerId' => $this->profile->crm_provider_id,\n 'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,\n 'type' => 'NOTE',\n ];\n\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);\n\n $metadata = [\n 'body' => $transcripts,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsEngagement = $this->client\n ->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $noteId = $hsEngagement->data->engagement->id;\n\n // Store crm logged id in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $noteId;\n $transcription->save();\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $payload = [\n 'properties' => $data,\n ];\n\n try {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n $this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);\n\n break;\n case FieldData::OBJECT_CONTACT:\n $this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_ACCOUNT:\n $this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_TASK:\n // Endpoint for Engagements not ready\n $engagements = [\n 'type' => 'TASK',\n ];\n $metadata = $data;\n $this->client->getInstance()->engagements()->update($objectId, $engagements, $metadata);\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $objectId],\n $metadata,\n );\n\n break;\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException $apiException) {\n $errorMessage = $apiException->getMessage();\n if ($apiException->getResponseBody()) {\n $responseBody = json_decode($apiException->getResponseBody(), true, 512, JSON_THROW_ON_ERROR);\n $errorMessage = $responseBody['message'] ?? $apiException->getMessage();\n }\n\n $this->logger->error(\n '[HubSpot] Update record failed',\n [\n 'objectType' => $objectType,\n 'objectId' => $objectId,\n 'payload' => $payload,\n 'reason' => $errorMessage,\n 'team' => $this->team->getUuid(),\n ]\n );\n\n throw new CrmException($errorMessage);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n return $this->client->getInstance()->deals()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_CONTACT:\n return $this->client->getInstance()->contacts()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_ACCOUNT:\n return $this->client->getInstance()->companies()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_TASK:\n return $this->client->getInstance()->engagements()->get($objectId)->toArray();\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n }\n\n /**\n * @throws BadRequest\n * @throws CrmException\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n $payload = [\n 'properties' => [\n [\n 'name' => 'dealstage',\n 'value' => $stage->crm_provider_id,\n ],\n ],\n ];\n\n try {\n $this->client->getInstance()->deals()->update($crmObject->crm_provider_id, $payload);\n } catch (BadRequest $badRequest) {\n if ($badRequest->getCode() === 403) {\n throw new CrmException(\n \"Sorry, you don't have permission to update this stage.\",\n $badRequest->getCode(),\n $badRequest,\n );\n }\n\n $this->logger->warning('[HubSpot] Stage update failed', [\n 'dealId' => $crmObject->crm_provider_id,\n 'payload' => $payload,\n 'message' => $badRequest->getMessage(),\n ]);\n\n throw $badRequest;\n }\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $url = null;\n $baseUrl = 'https://app.hubspot.com/contacts/' . $this->config->crm_provider_id . '/';\n\n switch ($objectType) {\n case 'account':\n $url = $baseUrl . 'company/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n case 'task':\n case 'activity':\n return null;\n\n // This should not be deep-linked as per JMNY-3934.\n //$url = $baseUrl.'tasks/list/view/all/?taskId='.$providerId;\n break;\n }\n\n return $url;\n }\n\n public function searchCalls(Carbon $from, Carbon $to, string $activityProvider): array\n {\n $this->logger->info('[HubSpot] Search calls', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $calls = [];\n $page = 1;\n\n do {\n try {\n $payload = $this->payloadBuilder->generateGetCallsPayload($from, $to, $activityProvider, $page);\n $response = $this->client->search('calls', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n $calls = array_merge($calls, $responseResults);\n $page++;\n } while (! empty($responseResults));\n\n return $calls;\n }\n\n public function searchCallsForPeriodByPage(Carbon $from, Carbon $to, int $page, bool $retry = true)\n {\n try {\n $payload = $this->payloadBuilder->generateSearchCallsByPeriodPayload($from, $to, $page);\n\n return $this->client->search('calls', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls for period failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallsForPeriodByPage($from, $to, $page, false);\n }\n\n return null;\n }\n }\n\n public function searchCallsForPeriod(Carbon $from, Carbon $to): Generator\n {\n $this->logger->info('[HubSpot] Search calls for period', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $page = 1;\n\n do {\n $response = $this->searchCallsForPeriodByPage($from, $to, $page);\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n\n $associationContacts = $this->getAssociationDataForCollection($responseResults, 'calls', 'contacts');\n $associationCompanies = $this->getAssociationDataForCollection($responseResults, 'calls', 'companies');\n $associationDeals = $this->getAssociationDataForCollection($responseResults, 'calls', 'deals');\n\n foreach ($responseResults as $call) {\n $call['associations'] = [\n 'contacts' => $this->importAssociationData($call, $associationContacts),\n 'companies' => $this->importAssociationData($call, $associationCompanies),\n 'deals' => $this->importAssociationData($call, $associationDeals),\n ];\n\n yield $call;\n }\n $page++;\n } while (! empty($responseResults));\n }\n\n public function getCall(string $callId): array\n {\n $this->logger->info('[HubSpot] Get call', [\n 'call_id' => $callId,\n ]);\n\n $searchAttributes = $this->payloadBuilder->getSearchCallAttributes();\n $endpoint = sprintf(\n 'https://api.hubapi.com/crm/v3/objects/calls/%s',\n $callId,\n );\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'GET',\n $endpoint,\n [],\n sprintf(\n 'properties=%s&associations=contacts,companies,deals',\n implode(',', $searchAttributes),\n ),\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Get call failed', [\n 'call_id' => $callId,\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n return empty($response) ? [] : $response->toArray();\n }\n\n public function bulkAddPlaybackURLToDescription(array $crmUpdateData): array\n {\n $crmUpdateBatches = array_chunk($crmUpdateData, self::BATCH_UPDATE_LIMIT);\n\n $updatedCrmIds = [];\n\n foreach ($crmUpdateBatches as $crmBatch) {\n $payload = $this->payloadBuilder->generatePlaybackAddUrlBatchPayload($crmBatch);\n $updateSuccess = $this->bulkAddPlaybackURLToDescriptionRequest($payload);\n if ($updateSuccess) {\n $updatedCrmIds = array_merge($updatedCrmIds, array_column($crmBatch, 'crm_id'));\n }\n }\n\n return $updatedCrmIds;\n }\n\n private function bulkAddPlaybackURLToDescriptionRequest(array $payload, bool $retry = true): bool\n {\n try {\n $this->client->getNewInstance()->crm()->objects()->batchApi()->update('calls', $payload);\n\n return true;\n } catch (\\HubSpot\\Client\\Crm\\Objects\\ApiException $e) {\n $response = json_decode($e->getResponseBody(), true);\n $retryAfter =\n isset($response['policyName'])\n && $response['policyName'] == self::TEN_SECONDLY_ROLLING_POLICY\n ? self::TEN_SECONDLY_ROLLING_LIMIT\n : 1;\n } catch (Exception $e) {\n $retryAfter = 1;\n }\n\n $this->logger->warning('[HubSpot] Bulk add playback url to CRM failed', [\n 'reason' => $e->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep($retryAfter);\n\n return $this->bulkAddPlaybackURLToDescriptionRequest($payload, false);\n }\n\n return false;\n }\n\n /**\n * Sometimes we have secondly rate limit error, then retry request after 1 second\n */\n public function searchCallByRecordingURLToken(string $playbackURLToken, bool $retry = true): array\n {\n $payload = $this->payloadBuilder->generateSearchCallByTokenPayload($playbackURLToken);\n\n $this->logger->info('[HubSpot] CRM Search by playback URL token requested', [\n 'request' => $payload,\n ]);\n\n try {\n $response = $this->client->search('calls', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search by playback URL token failed', [\n 'playbackURLToken' => $playbackURLToken,\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallByRecordingURLToken($playbackURLToken, false);\n }\n\n return [];\n }\n\n return empty($response['results']) ? [] : $response['results'][0];\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! $this->config->store_transcript) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n $transcriptionSegments = $this->transcriptionService->findTranscriptionByActivity($activity);\n\n if ($transcriptionSegments->isEmpty()) {\n return '';\n }\n\n $transcription = sprintf(\n '<p><strong>Transcript for %s</strong></p><p></p>',\n $activity->title ?? $activity->activity_title,\n );\n\n $roomOwnerParticipant = $activity->findParticipantRoomOwner();\n $roomOwnerParticipantId = $roomOwnerParticipant !== null\n ? $roomOwnerParticipant->getId()\n : null;\n\n\n $transcription .= $transcriptionSegments\n ->map(static function (array $transcriptionSegment) use ($roomOwnerParticipantId): string {\n $isOrganiser = $roomOwnerParticipantId === $transcriptionSegment['participantId']\n && $roomOwnerParticipantId !== null;\n $transcriptColor = $isOrganiser ? '#000000' : '#f0415a';\n\n return sprintf(\n '<span style=\"color: %s;\">%s | </span>%s',\n $transcriptColor,\n $transcriptionSegment['formattedStartsAt'],\n $transcriptionSegment['transcript'],\n );\n })\n ->implode('<br />');\n\n return $transcription;\n }\n\n /**\n * @param array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }> $options\n *\n * @return FieldData[]\n */\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $values = [];\n $sequence = 0;\n\n foreach ($options as $option) {\n $values[] = [\n 'value' => $option['value'] ?? $option['id'],\n 'label' => substr($option['label'], 0, 255),\n 'sequence' => $sequence++,\n ];\n }\n\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n $value['value'] = substr($value['value'], 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n if (($key = array_search($value['value'], $fieldsToPurge, false)) !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n public function saveTranscriptionSummaryAsNote(\n ActivityContract $activity,\n string $title,\n string $body,\n ?string $objectId,\n ?NoteObject $noteObject = null,\n ): ?string {\n if ($noteObject === null || $objectId === null) {\n return null;\n }\n\n /** @var User $user */\n $user = $activity->getUser();\n\n $profile = $this->assignCrmOwner($user, $activity);\n if (! $profile instanceof Profile) {\n return null;\n }\n\n $timestamp = Carbon::now($user->getTimezone())->getTimestamp() * 1000;\n $engagement = [\n 'active' => true,\n 'ownerId' => $profile->getAttribute('crm_provider_id'),\n 'timestamp' => $timestamp,\n 'type' => 'NOTE',\n ];\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $body = mb_strimwidth($body, 0, self::ENGAGEMENT_BODY_MAX_LENGTH);\n $metadata = [\n 'body' => $body,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsActivityId = $this->client->createNote(\n body: $body,\n ownerId: $profile->getCrmProviderId(),\n timestamp: $timestamp,\n objectId: $objectId,\n noteObject: $noteObject,\n );\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $this->logger->info('[HubSpot] Saving Transcription Summary as Note', [\n 'activity' => $activity->getUuid(),\n 'crmActivity' => $hsActivityId,\n ]);\n\n return $hsActivityId;\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function attachSummaryToActivity(ActivityContract $activity, string $summaryTitle, string $summaryContents): bool\n {\n $this->logger->info('[HubSpot] Attaching summary to activity', [\n 'activity' => $activity->getUuid(),\n 'summary_content' => $summaryContents,\n ]);\n\n if (! $activity instanceof Activity) {\n throw new InvalidArgumentException('Expected instance of Activity');\n }\n\n $summary = '<p><strong>' . $summaryTitle . '</strong></p>';\n $summary .= '<p>' . $summaryContents . '</p>';\n $metadata = $this->buildMetadataForSummaryUpdate($activity, $summary);\n\n try {\n $type = $this->matchActivityEngagementType($activity);\n $engagement = ['type' => $type];\n\n $this->client->updateEngagement($activity->getCrmProviderId(), $engagement, $metadata);\n } catch (Exception $e) {\n $this->logger->warning('[HubSpot] Update summary failed', [\n 'activity' => $activity->getUuid(),\n 'reason' => $e->getMessage(),\n ]);\n\n return false;\n }\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $activity->getCrmProviderId()],\n $metadata,\n );\n\n return true;\n }\n\n private function buildMetadataForSummaryUpdate(Activity $activity, string $summary): array\n {\n $descriptionField = $activity->getType() === Activity::TYPE_CONFERENCE ? 'internalMeetingNotes' : 'body';\n $engagement = $this->client->getEngagementData($activity->getCrmProviderId());\n // Meeting without internalMeetingNotes might mean it just does not have any notes;\n $description = $engagement['metadata'][$descriptionField] ?? null;\n\n if (empty($description)) {\n $data = $summary;\n } else {\n // avoid playbook url link to Jiminny being sent twice in the activity description\n $targetUrl = PlaybackUrlBuilder::build($activity);\n\n if (str_contains($description, $targetUrl)) {\n $jiminnyUrl = '<p><a href=\"' . $targetUrl . '\" title=\"Play at Jiminny\">Play at Jiminny</a></p>';\n $summary = str_replace($jiminnyUrl, '', $summary);\n\n $this->logger->info('[HubSpot] Summary modified', [\n 'activity' => $activity->getUuid(),\n 'target_url' => $jiminnyUrl,\n 'modified_summary_content' => $summary,\n ]);\n }\n\n $data = $description . '<p></p>' . $summary;\n }\n\n return [\n $descriptionField => $data,\n ];\n }\n\n public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity\n {\n return $this->syncRelatedActivityManager->fetchAndAssociateRelatedActivity($activity);\n }\n\n public function fetchRelatedActivity(Activity $activity): array\n {\n return [];\n }\n\n public function getDealsInBulk(array $dealIds): array\n {\n $payload = $this->payloadBuilder->getDealsInBulkPayload($dealIds);\n\n return $this->client->getPaginatedData($payload, 'deals');\n }\n\n /**\n * Extract deal IDs from HubSpot search response.\n *\n * @param array $hubspotResponse The raw HubSpot search API response.\n * @param bool $includeArchived Whether to include archived deals (default: false).\n *\n * @return string[] Array of deal IDs as strings.\n */\n public function extractDealIds(array $hubspotResponse, bool $includeArchived = false): array\n {\n if (empty($hubspotResponse['results'])) {\n return [];\n }\n\n return array_values(\n array_map(\n fn ($deal) => $deal['id'],\n array_filter(\n $hubspotResponse['results'],\n fn ($deal) => $includeArchived || empty($deal['archived'])\n )\n )\n );\n }\n\n public function matchActivityEngagementType(Activity $activity): string\n {\n return match ($activity->getType()) {\n Activity::TYPE_CONFERENCE => self::TYPE_MEETING,\n Activity::TYPE_SOFTPHONE, Activity::TYPE_SOFTPHONE_INBOUND => self::TYPE_CALL,\n default => self::TYPE_NOTE,\n };\n }\n\n private function assignCrmOwner(User $user, ActivityContract $activity): ?Profile\n {\n $profile = $user->getProfile();\n if ($profile instanceof Profile) {\n return $profile;\n }\n\n $this->logger->info('[HubSpot] Unable to save summary. No profile', [\n 'activity' => $activity->getUuid(),\n ]);\n\n return null;\n }\n\n private static function getDealsPipelinesEndpoint(): string\n {\n return self::API_URL . self::ENDPOINT_PIPELINES . self::PIPELINE_OBJECT_TYPE_DEALS;\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n $engagement = $this->client->getEngagementData($crmProviderId);\n\n return ! empty($engagement);\n } catch (HttpNotFoundException|BadRequest) {\n // Engagement not found in CRM - this is expected and permanent\n $this->logger->info('[Hubspot] Engagement not found during verification', [\n 'engagement_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse Generator;\nuse GuzzleHttp\\Exception\\RequestException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse InvalidArgumentException;\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Contracts\\Services\\Crm\\ClientInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\FetchRelatedActivityInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\HubspotInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SavePlaybackLinkToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SendSummaryToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Contracts\\ActivityContract;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\Layout;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Participant;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\ParticipantRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Hubspot\\Actions\\SyncArchivedProfilesAction;\nuse Jiminny\\Services\\Crm\\Hubspot\\Fields\\ValueNormalizer;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\OpportunitySyncTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncCrmEntitiesTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncFieldsTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\WriteCrmTrait;\nuse Jiminny\\Services\\Crm\\MatchDomainByEmailInterface;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\ResolveCompanyNameByEmailTrait;\nuse Jiminny\\Utils\\PlaybackUrlBuilder;\nuse Sentry;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse Throwable;\nuse UnexpectedValueException;\n\n/**\n * @phpstan-type CrmFieldDefinition array{\n * name: string,\n * label: string,\n * description: string,\n * type: string,\n * fieldType: string,\n * hidden: bool,\n * showCurrencySymbol: bool,\n * options: array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }\n */\nclass Service extends BaseService implements\n HubspotInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n SendSummaryToCrmInterface,\n MatchDomainByEmailInterface,\n SavePlaybackLinkToCrmInterface,\n RemoteEntityManipulationInterface,\n FetchRelatedActivityInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use ResolveCompanyNameByEmailTrait;\n use SyncCrmEntitiesTrait;\n use WriteCrmTrait;\n use SyncFieldsTrait;\n use OpportunitySyncTrait;\n\n private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;\n\n private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';\n private const int BATCH_UPDATE_LIMIT = 100;\n private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';\n private const int TEN_SECONDLY_ROLLING_LIMIT = 10;\n\n private const string TYPE_NOTE = 'NOTE';\n\n private const string TYPE_MEETING = 'MEETING';\n\n private const string TYPE_CALL = 'CALL';\n\n private const string API_URL = 'https://api.hubapi.com';\n\n // NB: v1 is legacy - v3 is the newest\n private const string ENDPOINT_PIPELINES = '/crm-pipelines/v1/pipelines/';\n private const string PIPELINE_OBJECT_TYPE_DEALS = 'deals';\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n /**\n * @var ClientInterface|Client\n */\n protected $client;\n protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;\n protected CrmEntityRepository $crmEntityRepository;\n protected ProspectPhotoPathService $prospectPhotoPathService;\n\n private SyncFieldAction $syncFieldAction;\n private PayloadBuilder $payloadBuilder;\n private SyncRelatedActivityManager $syncRelatedActivityManager;\n private SyncArchivedProfilesAction $syncArchivedProfilesAction;\n private WebhookSyncBatchProcessor $batchProcessor;\n\n public function __construct(\n Client $client,\n SyncFieldAction $syncFieldAction,\n PayloadBuilder $payloadBuilder,\n ProspectPhotoPathService $prospectPhotoPathService,\n SyncArchivedProfilesAction $syncArchivedProfilesAction,\n WebhookSyncBatchProcessor $batchProcessor,\n ) {\n parent::__construct();\n\n $this->client = $client;\n $this->syncFieldAction = $syncFieldAction;\n $this->prospectPhotoPathService = $prospectPhotoPathService;\n $this->payloadBuilder = $payloadBuilder;\n $this->syncArchivedProfilesAction = $syncArchivedProfilesAction;\n $this->batchProcessor = $batchProcessor;\n $this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->client,\n ]);\n $this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [\n 'client' => $this->client,\n 'payloadBuilder' => $this->payloadBuilder,\n 'logger' => $this->logger,\n ]);\n $this->crmEntityRepository = app(CrmEntityRepository::class);\n $this->dealFieldsService = app(DealFieldsService::class);\n }\n\n public function getDisplayName(): string\n {\n return 'HubSpot';\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);\n }\n\n public function getClient(): Client\n {\n /** @var Client */\n return $this->client;\n }\n\n /**\n * Convert raw field data into a format compatible with CRM APIs.\n *\n * @param bool $internal Direction of the conversion.\n * True is pulling from CRM, false normalize before sending to CRM.\n */\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return ValueNormalizer::normalize(\n fieldType: $fieldType,\n fieldValue: $fieldValue,\n isInbound: $internal,\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n /** @var Field $activityField */\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'activityType',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n // Outcome should always be provided calls/meetings.\n $fieldData = [\n [\n 'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',\n 'object_type' => Field::OBJECT_TASK,\n ],\n ];\n\n foreach ($fieldData as $data) {\n $field = $this->config->fields()->where($data)->first();\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n }\n\n return $fields;\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldData = FieldDefinitions::followupFieldsFilter();\n\n foreach ($fieldData as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function syncField(Field $field): void\n {\n switch ($field->object_type) {\n case Field::OBJECT_ACCOUNT:\n $crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_CONTACT:\n $crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_OPPORTUNITY:\n $crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_TASK:\n $this->syncSingleTaskField($field);\n\n return;\n default:\n return;\n }\n\n $this->syncFieldAction->execute($field, $crmField->toArray());\n }\n\n /**\n * @param array<array{\n * id:string,\n * label:string,\n * value?:string\n * }> $options\n *\n * @throws CrmException\n *\n * @return FieldData[]\n *\n */\n public function importPicklistValues(\n Field $field,\n array $options = [['id' => '', 'label' => '', 'value' => '']],\n ): array {\n if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {\n // We already have the options, no need to fetch them again\n return $this->importOptions($field, $options);\n }\n\n $options = [];\n\n switch ($field->getObjectType()) {\n case Field::OBJECT_ACCOUNT:\n $options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_CONTACT:\n $options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_OPPORTUNITY:\n // Hubspot has different endpoint for stages\n $options = $this->getClient()->fetchOpportunityFieldOptions($field);\n\n break;\n\n case Field::OBJECT_TASK:\n if ($field->getCrmProviderId() === 'disposition') {\n $options = $this->getClient()->fetchDispositionFieldOptions();\n } elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {\n $options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);\n }\n\n break;\n\n default:\n $this->logger->warning('Invalid object type', [\n 'object_type' => $field->getObjectType(),\n 'field_id' => $field->getId(),\n ]);\n\n throw new CrmException('Invalid object type');\n }\n\n return $this->importOptions($field, $options);\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n $missingStage = null;\n\n try {\n // Use the HubSpot API client instead of the SDK crmPipelines() method\n $endpoint = self::getDealsPipelinesEndpoint();\n $pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);\n $pipelines = $pipelinesResponse->data->results;\n } catch (RequestException|BadRequest $exception) {\n throw $exception;\n }\n\n foreach ($pipelines as $pipeline) {\n $stages = [];\n\n // We create a business process to contain the pipeline, and store all stages against it.\n $p = ResponseNormalize::normalizePipeline($pipeline);\n\n // Create/update business process for this pipeline\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => $p['active'],\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n // Create/update record type clone\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'is_selectable' => $p['active'],\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n // Stages - fetch all existing stages upfront to avoid N+1 queries\n $existingStages = $this->config->stages()\n ->withTrashed()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get()\n ->keyBy('crm_provider_id');\n\n foreach ($p['stages'] as $dealStage) {\n $s = ResponseNormalize::normalizeDealStage($dealStage);\n\n /** @var ?Stage $existingStage */\n $existingStage = $existingStages->get($s['id']);\n\n // Restore soft-deleted stages that are now active in HubSpot\n if ($existingStage?->trashed() && $s['active']) {\n $existingStage->restore();\n }\n\n // Upsert stage (updates soft-deleted records without restoring them)\n $stage = $this->config->stages()->withTrashed()->updateOrCreate([\n 'crm_provider_id' => $s['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($s['label'], 0, 50),\n 'label' => mb_strimwidth($s['label'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $s['displayOrder'],\n 'is_selectable' => $s['active'],\n 'probability' => $s['probability'] * 100,\n ]);\n\n if ($missingStageName === $s['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage->id;\n }\n\n $businessProcess->stages()->sync($stages);\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n try {\n $endpoint = 'https://api.hubapi.com/integrations/v1/me';\n $response = $this->client->getInstance()->getClient()->request('get', $endpoint);\n\n $accountData = $response->data;\n $this->config->update(['default_currency' => $accountData->currency]);\n } catch (BadRequest $e) {\n throw new CrmException('Could not sync the organization.', $e->getCode(), $e);\n }\n }\n\n /**\n * @inheritdoc\n *\n * @throws CrmException\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $this->syncArchivedProfilesAction->execute($this->team, $this->client, $this->config);\n\n try {\n $owners = $this->client->getOwners();\n } catch (\\HubSpot\\Client\\Crm\\Owners\\ApiException $e) {\n $this->logger->error('[HubSpot] Could not sync the profiles.', [\n 'team_id' => $this->team->getId(),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new CrmException('Could not sync the profiles.', $e->getCode(), $e);\n }\n\n $profileRepository = app(ProfileRepository::class);\n $teamRepository = app(TeamRepository::class);\n\n foreach ($owners as $owner) {\n if ($owner->getArchived()) {\n // not supposed to fetch archived, but log anyway\n $this->logger->warning('[HubSpot] Found archived owner', [\n 'crm_provider_id' => $owner->getId(),\n 'email' => $owner->getEmail(),\n ]);\n\n continue;\n }\n\n $email = $owner->getEmail();\n if ($email === null) {\n continue;\n }\n\n $user = $teamRepository->findActiveTeamMemberByEmail($this->team, $email);\n\n if (! $user instanceof User) {\n continue;\n }\n\n $profile = $profileRepository->updateOrCreateProfile($user, [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $owner->getId(),\n ]);\n\n if ($userToSearch && $userToSearch->getId() === $user->getId()) {\n return $profile;\n }\n }\n\n return null;\n }\n\n private function generateNameSearchPayload(string $name, int $offset, int $limit): array\n {\n $payload = [\n 'query' => $name,\n 'sorts' => [\n [\n 'propertyName' => 'modifieddate',\n 'direction' => 'DESCENDING',\n ],\n ],\n 'properties' => [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n 'industry',\n 'name',\n 'company',\n ],\n 'limit' => $limit,\n 'after' => $offset,\n ];\n\n $this->logger->debug('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n return $payload;\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n /** @var array<int, array<string, mixed>> */\n return Cache::remember(\n key: $this->team->getId() . $name . $count . $offset,\n ttl: 300,\n callback: function () use ($name, $offset, $count): array {\n $data = [];\n\n // Use the new V3 API to find contacts based on additional fields.\n foreach (['companies', 'contacts'] as $objectType) {\n $payload = $this->generateNameSearchPayload($name, $offset, $count);\n $type = $objectType === 'companies' ? 'account' : 'contact';\n\n try {\n $response = $this->client->search($objectType, $payload);\n\n // Build mapped list.\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n\n $objectName = $this->buildContactName($properties);\n\n $record = [\n 'crmId' => $object['id'],\n // Pass crmUrl to the FE, needed for success message in the extension when you log activity.\n 'crmUrl' => $this->generateProviderUrl($object['id'], $type),\n 'name' => $objectName,\n 'prospectType' => $type,\n 'phoneNumbers' => [],\n ];\n\n if ($type === 'account') {\n $record['industry'] = $properties['industry'] ?? null;\n } else {\n $record['title'] = $properties['jobtitle'] ?? null;\n $record['organization'] = $properties['company'] ?? null;\n }\n\n $countryCode = $this->buildContactCountry($properties);\n $parsedNumber = $this->buildContactPhone($countryCode, $properties);\n\n // Add phone number to record.\n if (! empty($parsedNumber['phone'])) {\n $record['phoneNumbers'][] = [\n 'number' => $parsedNumber['phone'],\n 'nationalFormat' => phone_national($countryCode, $parsedNumber['phone']),\n 'type' => 'phone',\n ];\n }\n\n // Add mobile phone number to record.\n if (! empty($properties['mobilephone'])) {\n $mobileNumber = phone_e164($countryCode, $properties['mobilephone']);\n if ($mobileNumber !== null) {\n $record['phoneNumbers'][] = [\n 'number' => $mobileNumber,\n 'nationalFormat' => phone_national($countryCode, $mobileNumber),\n 'type' => 'mobile',\n ];\n }\n }\n\n $data[] = $record;\n }\n } catch (BadRequest $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->getUuid(),\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n }\n\n return $data;\n },\n );\n }\n\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n\n if ($crmAccountId === null) {\n return $data;\n }\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n $closedStages = $this->getClosedDealStages();\n $payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(\n $this->config,\n $crmAccountId,\n $closedStages,\n );\n\n $results = $this->client->getPaginatedData($payload, 'deals');\n\n foreach ($results['results'] as $object) {\n $properties = $object['properties'];\n\n $amount = null;\n if (empty($properties['amount']) === false) {\n $currency = $properties['deal_currency_code'] ?? $this->config->default_currency;\n\n // Values can contain commas and any junk so strip them.\n $value = (float) preg_replace('/[^\\d.]/', '', $properties['amount']);\n $amount = formatCurrency($value, $currency);\n }\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n } else {\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', $properties['dealstage'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages(null, $properties['dealstage']);\n }\n }\n\n $recordType = null;\n if ($businessProcess) {\n $recordType = $businessProcess->recordTypes()->first();\n }\n\n $isWon = in_array($properties['dealstage'], $closedStages['won']);\n $isLost = in_array($properties['dealstage'], $closedStages['lost']);\n\n $record = [\n 'crmId' => $object['id'],\n 'name' => $properties['dealname'] ?? 'Unknown Deal',\n 'value' => $amount,\n 'won' => $isWon,\n 'closed' => $isWon || $isLost,\n 'stage' => [\n 'id' => $stage?->getUuid() ?? '',\n 'name' => $stage?->getName() ?? '',\n ],\n ];\n\n if ($recordType) {\n $record += [\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n }\n\n if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = [];\n switch ($objectType) {\n case 'contact':\n $hsObject = 'contact';\n\n break;\n case 'account':\n $hsObject = 'company';\n\n break;\n default:\n // This is a hack to prioritise and override a contact/company with a deal.\n if ($opportunityId) {\n $hsObject = 'deal';\n $objectId = $opportunityId;\n } else {\n throw new InvalidArgumentException('Object type not supported.');\n }\n }\n\n $engagementTypes = ['meetings', 'tasks'];\n\n foreach ($engagementTypes as $engagementType) {\n $payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);\n\n $this->logger->info('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n $engagements = $this->client->getPaginatedData($payload, $engagementType);\n\n foreach ($engagements['results'] as $engagement) {\n if ($engagementType == 'meetings') {\n $title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';\n } elseif ($engagementType == 'tasks') {\n $title = $engagement['properties']['hs_task_subject'];\n } else {\n $title = 'Scheduled meeting';\n }\n\n $data[] = [\n 'crmId' => $engagement['id'],\n 'subject' => $title,\n 'due' => $engagement['properties']['hs_timestamp'],\n 'type' => $engagement['properties']['hs_activity_type'] ?? null,\n ];\n }\n }\n\n usort($data, function ($item1, $item2) {\n return $item2['due'] <=> $item1['due'];\n });\n\n return $data;\n }\n\n /**\n * Try to find CRM Objects using email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $contactProperties = [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n ];\n $contact = null;\n $account = null;\n\n try {\n $hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);\n\n if ($hsContact) {\n $contact = $this->importContact($hsContact);\n $account = $contact->account;\n }\n\n $data = $this->convertCrmData($contact, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n } catch (BadRequest $e) {\n $this->logger->warning('[HubSpot] Search failed', [\n 'team_id' => $this->team->getId(),\n 'search_identifier' => $email,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return null;\n }\n\n public function getDomain(string $email): ?string\n {\n return $this->getDomainFromEmail($email);\n }\n\n /**\n * Try to find CRM objects using domain name of the email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByDomain(string $domain, ?int $userId = null): ?array\n {\n $companyName = $domain;\n\n // Try to find a company matching their email domain.\n $companyProperties = [\n 'country',\n 'phone',\n 'name',\n 'hs_avatar_filemanager_key',\n 'industry',\n 'hubspot_owner_id',\n 'domain',\n ];\n\n try {\n $hsAccounts = $this->client\n ->getInstance()\n ->companies()\n ->searchByDomain($companyName, $companyProperties);\n } catch (Throwable $e) {\n $this->logger->info('[HubSpot] Search failed', [\n 'error' => $e->getMessage(),\n 'domain' => $domain,\n ]);\n\n return null;\n }\n\n $account = null;\n // If there are multiple accounts, don't guess, we'll ask later.\n if (\\count($hsAccounts->data->results) === 1) {\n // Persist this remote object.\n $account = $this->syncAccount($hsAccounts->data->results[0]->companyId);\n }\n\n $data = $this->convertCrmData(null, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array\n {\n $countryCode = null;\n if ($contact && $contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account && $account->country_code) {\n $countryCode = $account->country_code;\n }\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n // If there are multiple opportunities, don't guess, we'll ask later.\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n protected function getCacheKey(string $object, ?int $userId = null): ?string\n {\n $key = $this->team->getId() . $object;\n $keySuffix = $this->getOwnerKeySuffix($userId);\n\n return $key . $keySuffix;\n }\n\n private function getOwnerKeySuffix(?int $userId = null): string\n {\n return $userId === null ? '' : (string) $userId;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n if (str_contains($phone, '**')) {\n return null;\n }\n\n // trim all whitespaces if present so the lookup doesn't fail\n $phone = str_replace(' ', '', $phone);\n\n // Check if the user is internal.\n if ($this->isPhoneNumberOfTeamMember($phone)) {\n return null;\n }\n\n $response = $this->searchForPhoneNumber($phone);\n if (empty($response)) {\n return null;\n }\n\n // This would ideally importContact instead but the response type differs.\n $contact = $this->findAndSyncContact($response['results'][0]['id']);\n if (! $contact instanceof Contact) {\n return null;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n\n try {\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (Exception $e) {\n $this->logger->debug('[HubSpot] Opportunity failed to sync.', [\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n private function isPhoneNumberOfTeamMember(string $phone): bool\n {\n $teamRepository = app(TeamRepository::class);\n $user = $teamRepository->findTeamMemberByPhone($this->team, $phone);\n\n if ($user instanceof User) {\n return true;\n }\n\n return false;\n }\n\n private function findAndSyncContact(string $crmId): ?Contact\n {\n try {\n return $this->syncContact($crmId);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'reason' => $exception->getMessage(),\n ]);\n\n return null;\n }\n }\n\n private function hasResults(array $response): bool\n {\n return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;\n }\n\n private function searchForPhoneNumber(string $phone): array\n {\n // Normalizes the provided phone number for the API search.\n $normalizedPhone = $this->normalizePhoneNumber($phone);\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);\n\n $this->logger->info('[HubSpot] Phone match search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);\n\n if (! $this->hasResults($response)) {\n $nationalPhone = preg_replace('/\\D/', '', phone_national(null, $phone));\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);\n\n $this->logger->info('[HubSpot] Phone match national number search triggered', [\n 'phone' => $phone,\n 'nationalPhone' => $nationalPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n if (! $this->hasResults($response)) {\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);\n\n $this->logger->info('[HubSpot] Phone match alternative search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n return $this->hasResults($response) ? $response : [];\n }\n\n private function handlePhoneSearchRequest(string $phone, array $payload): array\n {\n try {\n return $this->client->search('contacts', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'phone' => $phone,\n 'reason' => $exception->getMessage(),\n ]);\n\n return [];\n }\n }\n\n private function normalizePhoneNumber(string $phone): string\n {\n return ltrim(phone_e164(null, $phone), '+0');\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $cacheKey = $this->getCacheKey($name, $userId);\n\n $result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {\n $payload = $this->payloadBuilder->generateSearchContactsByNamePayload(\n $name,\n $this->getContactFields()\n );\n\n $hsContacts = $this->client->getPaginatedData($payload, 'contact');\n if (empty($hsContacts['results'])) {\n return false;\n }\n\n $contact = $this->importContact($hsContacts['results'][0]);\n if ($contact === null) {\n return false;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n });\n\n return is_array($result) ? $result : null;\n }\n\n\n private function convertActivityAssociations(Activity $activity): array\n {\n return [\n 'contactIds' => $this->getParticipantsIds($activity),\n 'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],\n 'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],\n 'ownerIds' => [],\n ];\n }\n\n private function getParticipantsIds(Activity $activity): array\n {\n $attendees = [];\n\n $participantRepository = app(ParticipantRepository::class);\n $participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);\n foreach ($participants as $participant) {\n if ($participant->user_id || $participant->isCoach()) {\n continue;\n }\n\n $contact = $participant->contact()->first();\n if ($contact && $contact->crm_provider_id) {\n $attendees[] = $contact->crm_provider_id;\n } else {\n if (! empty($participant->name)) {\n $attendeeData = $this->fetchMissingAttendeeInfo($participant);\n }\n if (! empty($attendeeData['id'])) {\n $attendees[] = $attendeeData['id'];\n }\n }\n }\n\n if ($activity->hasContact()) {\n $attendees[] = $activity->contact->crm_provider_id;\n }\n\n return array_unique($attendees);\n }\n\n private function fetchMissingAttendeeInfo(Participant $participant): array\n {\n // Check if we need to look inside an account context.\n $activity = $participant->getActivity();\n $companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;\n\n // First check the local data.\n /** @var Contact[] $contacts */\n $contacts = $this->team->contacts()\n ->with('account')\n ->where('name', $participant->name)\n ->whereNotNull('email')\n ->get();\n\n foreach ($contacts as $contact) {\n // If we have a company in scope, check the contact is associated to it.\n if (\n $companyId !== null\n && ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)\n ) {\n continue;\n }\n\n return [\n 'id' => $contact->crm_provider_id,\n 'email' => $contact->email,\n ];\n }\n\n $payload = $this->generateNameSearchPayload($participant->name, 0, 20);\n\n try {\n $response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);\n\n // TODO add some logic to choose the most suitable contact if multiple\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n if (empty($object['properties']) === false) {\n // Check the company matches the contact.\n // Todo: Move this check inside the API search.\n if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {\n continue;\n }\n\n return [\n 'id' => $object['id'],\n 'email' => $properties['email'],\n ];\n }\n }\n } catch (Exception $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->id_string,\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [];\n }\n\n /**\n * Store transcripts as note engagement.\n *\n * @throws Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // For HS no need to check if Crm profile - Log Notes field is enabled\n // We only check if store_transcript toggle is enabled on crm profile.\n $engagement = [\n 'active' => true,\n 'ownerId' => $this->profile->crm_provider_id,\n 'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,\n 'type' => 'NOTE',\n ];\n\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);\n\n $metadata = [\n 'body' => $transcripts,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsEngagement = $this->client\n ->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $noteId = $hsEngagement->data->engagement->id;\n\n // Store crm logged id in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $noteId;\n $transcription->save();\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $payload = [\n 'properties' => $data,\n ];\n\n try {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n $this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);\n\n break;\n case FieldData::OBJECT_CONTACT:\n $this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_ACCOUNT:\n $this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_TASK:\n // Endpoint for Engagements not ready\n $engagements = [\n 'type' => 'TASK',\n ];\n $metadata = $data;\n $this->client->getInstance()->engagements()->update($objectId, $engagements, $metadata);\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $objectId],\n $metadata,\n );\n\n break;\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException $apiException) {\n $errorMessage = $apiException->getMessage();\n if ($apiException->getResponseBody()) {\n $responseBody = json_decode($apiException->getResponseBody(), true, 512, JSON_THROW_ON_ERROR);\n $errorMessage = $responseBody['message'] ?? $apiException->getMessage();\n }\n\n $this->logger->error(\n '[HubSpot] Update record failed',\n [\n 'objectType' => $objectType,\n 'objectId' => $objectId,\n 'payload' => $payload,\n 'reason' => $errorMessage,\n 'team' => $this->team->getUuid(),\n ]\n );\n\n throw new CrmException($errorMessage);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n return $this->client->getInstance()->deals()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_CONTACT:\n return $this->client->getInstance()->contacts()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_ACCOUNT:\n return $this->client->getInstance()->companies()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_TASK:\n return $this->client->getInstance()->engagements()->get($objectId)->toArray();\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n }\n\n /**\n * @throws BadRequest\n * @throws CrmException\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n $payload = [\n 'properties' => [\n [\n 'name' => 'dealstage',\n 'value' => $stage->crm_provider_id,\n ],\n ],\n ];\n\n try {\n $this->client->getInstance()->deals()->update($crmObject->crm_provider_id, $payload);\n } catch (BadRequest $badRequest) {\n if ($badRequest->getCode() === 403) {\n throw new CrmException(\n \"Sorry, you don't have permission to update this stage.\",\n $badRequest->getCode(),\n $badRequest,\n );\n }\n\n $this->logger->warning('[HubSpot] Stage update failed', [\n 'dealId' => $crmObject->crm_provider_id,\n 'payload' => $payload,\n 'message' => $badRequest->getMessage(),\n ]);\n\n throw $badRequest;\n }\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $url = null;\n $baseUrl = 'https://app.hubspot.com/contacts/' . $this->config->crm_provider_id . '/';\n\n switch ($objectType) {\n case 'account':\n $url = $baseUrl . 'company/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n case 'task':\n case 'activity':\n return null;\n\n // This should not be deep-linked as per JMNY-3934.\n //$url = $baseUrl.'tasks/list/view/all/?taskId='.$providerId;\n break;\n }\n\n return $url;\n }\n\n public function searchCalls(Carbon $from, Carbon $to, string $activityProvider): array\n {\n $this->logger->info('[HubSpot] Search calls', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $calls = [];\n $page = 1;\n\n do {\n try {\n $payload = $this->payloadBuilder->generateGetCallsPayload($from, $to, $activityProvider, $page);\n $response = $this->client->search('calls', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n $calls = array_merge($calls, $responseResults);\n $page++;\n } while (! empty($responseResults));\n\n return $calls;\n }\n\n public function searchCallsForPeriodByPage(Carbon $from, Carbon $to, int $page, bool $retry = true)\n {\n try {\n $payload = $this->payloadBuilder->generateSearchCallsByPeriodPayload($from, $to, $page);\n\n return $this->client->search('calls', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls for period failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallsForPeriodByPage($from, $to, $page, false);\n }\n\n return null;\n }\n }\n\n public function searchCallsForPeriod(Carbon $from, Carbon $to): Generator\n {\n $this->logger->info('[HubSpot] Search calls for period', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $page = 1;\n\n do {\n $response = $this->searchCallsForPeriodByPage($from, $to, $page);\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n\n $associationContacts = $this->getAssociationDataForCollection($responseResults, 'calls', 'contacts');\n $associationCompanies = $this->getAssociationDataForCollection($responseResults, 'calls', 'companies');\n $associationDeals = $this->getAssociationDataForCollection($responseResults, 'calls', 'deals');\n\n foreach ($responseResults as $call) {\n $call['associations'] = [\n 'contacts' => $this->importAssociationData($call, $associationContacts),\n 'companies' => $this->importAssociationData($call, $associationCompanies),\n 'deals' => $this->importAssociationData($call, $associationDeals),\n ];\n\n yield $call;\n }\n $page++;\n } while (! empty($responseResults));\n }\n\n public function getCall(string $callId): array\n {\n $this->logger->info('[HubSpot] Get call', [\n 'call_id' => $callId,\n ]);\n\n $searchAttributes = $this->payloadBuilder->getSearchCallAttributes();\n $endpoint = sprintf(\n 'https://api.hubapi.com/crm/v3/objects/calls/%s',\n $callId,\n );\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'GET',\n $endpoint,\n [],\n sprintf(\n 'properties=%s&associations=contacts,companies,deals',\n implode(',', $searchAttributes),\n ),\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Get call failed', [\n 'call_id' => $callId,\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n return empty($response) ? [] : $response->toArray();\n }\n\n public function bulkAddPlaybackURLToDescription(array $crmUpdateData): array\n {\n $crmUpdateBatches = array_chunk($crmUpdateData, self::BATCH_UPDATE_LIMIT);\n\n $updatedCrmIds = [];\n\n foreach ($crmUpdateBatches as $crmBatch) {\n $payload = $this->payloadBuilder->generatePlaybackAddUrlBatchPayload($crmBatch);\n $updateSuccess = $this->bulkAddPlaybackURLToDescriptionRequest($payload);\n if ($updateSuccess) {\n $updatedCrmIds = array_merge($updatedCrmIds, array_column($crmBatch, 'crm_id'));\n }\n }\n\n return $updatedCrmIds;\n }\n\n private function bulkAddPlaybackURLToDescriptionRequest(array $payload, bool $retry = true): bool\n {\n try {\n $this->client->getNewInstance()->crm()->objects()->batchApi()->update('calls', $payload);\n\n return true;\n } catch (\\HubSpot\\Client\\Crm\\Objects\\ApiException $e) {\n $response = json_decode($e->getResponseBody(), true);\n $retryAfter =\n isset($response['policyName'])\n && $response['policyName'] == self::TEN_SECONDLY_ROLLING_POLICY\n ? self::TEN_SECONDLY_ROLLING_LIMIT\n : 1;\n } catch (Exception $e) {\n $retryAfter = 1;\n }\n\n $this->logger->warning('[HubSpot] Bulk add playback url to CRM failed', [\n 'reason' => $e->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep($retryAfter);\n\n return $this->bulkAddPlaybackURLToDescriptionRequest($payload, false);\n }\n\n return false;\n }\n\n /**\n * Sometimes we have secondly rate limit error, then retry request after 1 second\n */\n public function searchCallByRecordingURLToken(string $playbackURLToken, bool $retry = true): array\n {\n $payload = $this->payloadBuilder->generateSearchCallByTokenPayload($playbackURLToken);\n\n $this->logger->info('[HubSpot] CRM Search by playback URL token requested', [\n 'request' => $payload,\n ]);\n\n try {\n $response = $this->client->search('calls', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search by playback URL token failed', [\n 'playbackURLToken' => $playbackURLToken,\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallByRecordingURLToken($playbackURLToken, false);\n }\n\n return [];\n }\n\n return empty($response['results']) ? [] : $response['results'][0];\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! $this->config->store_transcript) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n $transcriptionSegments = $this->transcriptionService->findTranscriptionByActivity($activity);\n\n if ($transcriptionSegments->isEmpty()) {\n return '';\n }\n\n $transcription = sprintf(\n '<p><strong>Transcript for %s</strong></p><p></p>',\n $activity->title ?? $activity->activity_title,\n );\n\n $roomOwnerParticipant = $activity->findParticipantRoomOwner();\n $roomOwnerParticipantId = $roomOwnerParticipant !== null\n ? $roomOwnerParticipant->getId()\n : null;\n\n\n $transcription .= $transcriptionSegments\n ->map(static function (array $transcriptionSegment) use ($roomOwnerParticipantId): string {\n $isOrganiser = $roomOwnerParticipantId === $transcriptionSegment['participantId']\n && $roomOwnerParticipantId !== null;\n $transcriptColor = $isOrganiser ? '#000000' : '#f0415a';\n\n return sprintf(\n '<span style=\"color: %s;\">%s | </span>%s',\n $transcriptColor,\n $transcriptionSegment['formattedStartsAt'],\n $transcriptionSegment['transcript'],\n );\n })\n ->implode('<br />');\n\n return $transcription;\n }\n\n /**\n * @param array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }> $options\n *\n * @return FieldData[]\n */\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $values = [];\n $sequence = 0;\n\n foreach ($options as $option) {\n $values[] = [\n 'value' => $option['value'] ?? $option['id'],\n 'label' => substr($option['label'], 0, 255),\n 'sequence' => $sequence++,\n ];\n }\n\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n $value['value'] = substr($value['value'], 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n if (($key = array_search($value['value'], $fieldsToPurge, false)) !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n public function saveTranscriptionSummaryAsNote(\n ActivityContract $activity,\n string $title,\n string $body,\n ?string $objectId,\n ?NoteObject $noteObject = null,\n ): ?string {\n if ($noteObject === null || $objectId === null) {\n return null;\n }\n\n /** @var User $user */\n $user = $activity->getUser();\n\n $profile = $this->assignCrmOwner($user, $activity);\n if (! $profile instanceof Profile) {\n return null;\n }\n\n $timestamp = Carbon::now($user->getTimezone())->getTimestamp() * 1000;\n $engagement = [\n 'active' => true,\n 'ownerId' => $profile->getAttribute('crm_provider_id'),\n 'timestamp' => $timestamp,\n 'type' => 'NOTE',\n ];\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $body = mb_strimwidth($body, 0, self::ENGAGEMENT_BODY_MAX_LENGTH);\n $metadata = [\n 'body' => $body,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsActivityId = $this->client->createNote(\n body: $body,\n ownerId: $profile->getCrmProviderId(),\n timestamp: $timestamp,\n objectId: $objectId,\n noteObject: $noteObject,\n );\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $this->logger->info('[HubSpot] Saving Transcription Summary as Note', [\n 'activity' => $activity->getUuid(),\n 'crmActivity' => $hsActivityId,\n ]);\n\n return $hsActivityId;\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function attachSummaryToActivity(ActivityContract $activity, string $summaryTitle, string $summaryContents): bool\n {\n $this->logger->info('[HubSpot] Attaching summary to activity', [\n 'activity' => $activity->getUuid(),\n 'summary_content' => $summaryContents,\n ]);\n\n if (! $activity instanceof Activity) {\n throw new InvalidArgumentException('Expected instance of Activity');\n }\n\n $summary = '<p><strong>' . $summaryTitle . '</strong></p>';\n $summary .= '<p>' . $summaryContents . '</p>';\n $metadata = $this->buildMetadataForSummaryUpdate($activity, $summary);\n\n try {\n $type = $this->matchActivityEngagementType($activity);\n $engagement = ['type' => $type];\n\n $this->client->updateEngagement($activity->getCrmProviderId(), $engagement, $metadata);\n } catch (Exception $e) {\n $this->logger->warning('[HubSpot] Update summary failed', [\n 'activity' => $activity->getUuid(),\n 'reason' => $e->getMessage(),\n ]);\n\n return false;\n }\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $activity->getCrmProviderId()],\n $metadata,\n );\n\n return true;\n }\n\n private function buildMetadataForSummaryUpdate(Activity $activity, string $summary): array\n {\n $descriptionField = $activity->getType() === Activity::TYPE_CONFERENCE ? 'internalMeetingNotes' : 'body';\n $engagement = $this->client->getEngagementData($activity->getCrmProviderId());\n // Meeting without internalMeetingNotes might mean it just does not have any notes;\n $description = $engagement['metadata'][$descriptionField] ?? null;\n\n if (empty($description)) {\n $data = $summary;\n } else {\n // avoid playbook url link to Jiminny being sent twice in the activity description\n $targetUrl = PlaybackUrlBuilder::build($activity);\n\n if (str_contains($description, $targetUrl)) {\n $jiminnyUrl = '<p><a href=\"' . $targetUrl . '\" title=\"Play at Jiminny\">Play at Jiminny</a></p>';\n $summary = str_replace($jiminnyUrl, '', $summary);\n\n $this->logger->info('[HubSpot] Summary modified', [\n 'activity' => $activity->getUuid(),\n 'target_url' => $jiminnyUrl,\n 'modified_summary_content' => $summary,\n ]);\n }\n\n $data = $description . '<p></p>' . $summary;\n }\n\n return [\n $descriptionField => $data,\n ];\n }\n\n public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity\n {\n return $this->syncRelatedActivityManager->fetchAndAssociateRelatedActivity($activity);\n }\n\n public function fetchRelatedActivity(Activity $activity): array\n {\n return [];\n }\n\n public function getDealsInBulk(array $dealIds): array\n {\n $payload = $this->payloadBuilder->getDealsInBulkPayload($dealIds);\n\n return $this->client->getPaginatedData($payload, 'deals');\n }\n\n /**\n * Extract deal IDs from HubSpot search response.\n *\n * @param array $hubspotResponse The raw HubSpot search API response.\n * @param bool $includeArchived Whether to include archived deals (default: false).\n *\n * @return string[] Array of deal IDs as strings.\n */\n public function extractDealIds(array $hubspotResponse, bool $includeArchived = false): array\n {\n if (empty($hubspotResponse['results'])) {\n return [];\n }\n\n return array_values(\n array_map(\n fn ($deal) => $deal['id'],\n array_filter(\n $hubspotResponse['results'],\n fn ($deal) => $includeArchived || empty($deal['archived'])\n )\n )\n );\n }\n\n public function matchActivityEngagementType(Activity $activity): string\n {\n return match ($activity->getType()) {\n Activity::TYPE_CONFERENCE => self::TYPE_MEETING,\n Activity::TYPE_SOFTPHONE, Activity::TYPE_SOFTPHONE_INBOUND => self::TYPE_CALL,\n default => self::TYPE_NOTE,\n };\n }\n\n private function assignCrmOwner(User $user, ActivityContract $activity): ?Profile\n {\n $profile = $user->getProfile();\n if ($profile instanceof Profile) {\n return $profile;\n }\n\n $this->logger->info('[HubSpot] Unable to save summary. No profile', [\n 'activity' => $activity->getUuid(),\n ]);\n\n return null;\n }\n\n private static function getDealsPipelinesEndpoint(): string\n {\n return self::API_URL . self::ENDPOINT_PIPELINES . self::PIPELINE_OBJECT_TYPE_DEALS;\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n $engagement = $this->client->getEngagementData($crmProviderId);\n\n return ! empty($engagement);\n } catch (HttpNotFoundException|BadRequest) {\n // Engagement not found in CRM - this is expected and permanent\n $this->logger->info('[Hubspot] Engagement not found during verification', [\n 'engagement_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3419229447380999607
|
-465194999110035353
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Show Replace Field
Search History
doSearch
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/1
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Code changed:
Hide
Sync Changes
Hide This Notification
7
48
1
33
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Hubspot;
use Carbon\Carbon;
use Exception;
use Generator;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Cache;
use InvalidArgumentException;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\FetchRelatedActivityInterface;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SavePlaybackLinkToCrmInterface;
use Jiminny\Contracts\Services\Crm\SendSummaryToCrmInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Contracts\ActivityContract;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Participant;
use Jiminny\Models\Playbook;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\ParticipantRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Hubspot\Actions\SyncArchivedProfilesAction;
use Jiminny\Services\Crm\Hubspot\Fields\ValueNormalizer;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\OpportunitySyncTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncCrmEntitiesTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncFieldsTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\WriteCrmTrait;
use Jiminny\Services\Crm\MatchDomainByEmailInterface;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\ResolveCompanyNameByEmailTrait;
use Jiminny\Utils\PlaybackUrlBuilder;
use Sentry;
use SevenShores\Hubspot\Exceptions\BadRequest;
use Throwable;
use UnexpectedValueException;
/**
* @phpstan-type CrmFieldDefinition array{
* name: string,
* label: string,
* description: string,
* type: string,
* fieldType: string,
* hidden: bool,
* showCurrencySymbol: bool,
* options: array<array{
* id: string,
* label: string,
* value?: string,
* }
*/
class Service extends BaseService implements
HubspotInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
SendSummaryToCrmInterface,
MatchDomainByEmailInterface,
SavePlaybackLinkToCrmInterface,
RemoteEntityManipulationInterface,
FetchRelatedActivityInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use ResolveCompanyNameByEmailTrait;
use SyncCrmEntitiesTrait;
use WriteCrmTrait;
use SyncFieldsTrait;
use OpportunitySyncTrait;
private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;
private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';
private const int BATCH_UPDATE_LIMIT = 100;
private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';
private const int TEN_SECONDLY_ROLLING_LIMIT = 10;
private const string TYPE_NOTE = 'NOTE';
private const string TYPE_MEETING = 'MEETING';
private const string TYPE_CALL = 'CALL';
private const string API_URL = '[URL_WITH_CREDENTIALS] ClientInterface|Client
*/
protected $client;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected ProspectPhotoPathService $prospectPhotoPathService;
private SyncFieldAction $syncFieldAction;
private PayloadBuilder $payloadBuilder;
private SyncRelatedActivityManager $syncRelatedActivityManager;
private SyncArchivedProfilesAction $syncArchivedProfilesAction;
private WebhookSyncBatchProcessor $batchProcessor;
public function __construct(
Client $client,
SyncFieldAction $syncFieldAction,
PayloadBuilder $payloadBuilder,
ProspectPhotoPathService $prospectPhotoPathService,
SyncArchivedProfilesAction $syncArchivedProfilesAction,
WebhookSyncBatchProcessor $batchProcessor,
) {
parent::__construct();
$this->client = $client;
$this->syncFieldAction = $syncFieldAction;
$this->prospectPhotoPathService = $prospectPhotoPathService;
$this->payloadBuilder = $payloadBuilder;
$this->syncArchivedProfilesAction = $syncArchivedProfilesAction;
$this->batchProcessor = $batchProcessor;
$this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [
'client' => $this->client,
'payloadBuilder' => $this->payloadBuilder,
'logger' => $this->logger,
]);
$this->crmEntityRepository = app(CrmEntityRepository::class);
$this->dealFieldsService = app(DealFieldsService::class);
}
public function getDisplayName(): string
{
return 'HubSpot';
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);
}
public function getClient(): Client
{
/** @var Client */
return $this->client;
}
/**
* Convert raw field data into a format compatible with CRM APIs.
*
* @param bool $internal Direction of the conversion.
* True is pulling from CRM, false normalize before sending to CRM.
*/
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return ValueNormalizer::normalize(
fieldType: $fieldType,
fieldValue: $fieldValue,
isInbound: $internal,
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'activityType',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
/**
* @inheritdoc
*/
public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
// Outcome should always be provided calls/meetings.
$fieldData = [
[
'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',
'object_type' => Field::OBJECT_TASK,
],
];
foreach ($fieldData as $data) {
$field = $this->config->fields()->where($data)->first();
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
}
return $fields;
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function syncField(Field $field): void
{
switch ($field->object_type) {
case Field::OBJECT_ACCOUNT:
$crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_CONTACT:
$crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_OPPORTUNITY:
$crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_TASK:
$this->syncSingleTaskField($field);
return;
default:
return;
}
$this->syncFieldAction->execute($field, $crmField->toArray());
}
/**
* @param array<array{
* id:string,
* label:string,
* value?:string
* }> $options
*
* @throws CrmException
*
* @return FieldData[]
*
*/
public function importPicklistValues(
Field $field,
array $options = [['id' => '', 'label' => '', 'value' => '']],
): array {
if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {
// We already have the options, no need to fetch them again
return $this->importOptions($field, $options);
}
$options = [];
switch ($field->getObjectType()) {
case Field::OBJECT_ACCOUNT:
$options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());
break;
case Field::OBJECT_CONTACT:
$options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());
break;
case Field::OBJECT_OPPORTUNITY:
// Hubspot has different endpoint for stages
$options = $this->getClient()->fetchOpportunityFieldOptions($field);
break;
case Field::OBJECT_TASK:
if ($field->getCrmProviderId() === 'disposition') {
$options = $this->getClient()->fetchDispositionFieldOptions();
} elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {
$options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);
}
break;
default:
$this->logger->warning('Invalid object type', [
'object_type' => $field->getObjectType(),
'field_id' => $field->getId(),
]);
throw new CrmException('Invalid object type');
}
return $this->importOptions($field, $options);
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
$missingStage = null;
try {
// Use the HubSpot API client instead of the SDK crmPipelines() method
$endpoint = self::getDealsPipelinesEndpoint();
$pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);
$pipelines = $pipelinesResponse->data->results;
} catch (RequestException|BadRequest $exception) {
throw $exception;
}
foreach ($pipelines as $pipeline) {
$stages = [];
// We create a business process to contain the pipeline, and store all stages against it.
$p = ResponseNormalize::normalizePipeline($pipeline);
// Create/update business process for this pipeline
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => $p['active'],
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
// Create/update record type clone
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'is_selectable' => $p['active'],
'business_process_id' => $businessProcess->id ?? null,
]);
// Stages - fetch all existing stages upfront to avoid N+1 queries
$existingStages = $this->config->stages()
->withTrashed()
->where('type', Stage::TYPE_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
foreach ($p['stages'] as $dealStage) {
$s = ResponseNormalize::normalizeDealStage($dealStage);
/** @var ?Stage $existingStage */
$existingStage = $existingStages->get($s['id']);
// Restore soft-deleted stages that are now active in HubSpot
if ($existingStage?->trashed() && $s['active']) {
$existingStage->restore();
}
// Upsert stage (updates soft-deleted records without restoring them)
$stage = $this->config->stages()->withTrashed()->updateOrCreate([
'crm_provider_id' => $s['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($s['label'], 0, 50),
'label' => mb_strimwidth($s['label'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $s['displayOrder'],
'is_selectable' => $s['active'],
'probability' => $s['probability'] * 100,
]);
if ($missingStageName === $s['id']) {
$missingStage = $stage;
}
$stages[] = $stage->id;
}
$businessProcess->stages()->sync($stages);
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
try {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
/** @var array<int, array<string, mixed>> */
return Cache::remember(
key: $this->team->getId() . $name . $count . $offset,
ttl: 300,
callback: function () use ($name, $offset, $count): array {
$data = [];
// Use the new V3 API to find contacts based on additional fields.
foreach (['companies', 'contacts'] as $objectType) {
$payload = $this->generateNameSearchPayload($name, $offset, $count);
$type = $objectType === 'companies' ? 'account' : 'contact';
try {
$response = $this->client->search($objectType, $payload);
// Build mapped list.
foreach ($response['results'] as $object) {
$properties = $object['properties'];
$objectName = $this->buildContactName($properties);
$record = [
'crmId' => $object['id'],
// Pass crmUrl to the FE, needed for success message in the extension when you log activity.
'crmUrl' => $this->generateProviderUrl($object['id'], $type),
'name' => $objectName,
'prospectType' => $type,
'phoneNumbers' => [],
];
if ($type === 'account') {
$record['industry'] = $properties['industry'] ?? null;
} else {
$record['title'] = $properties['jobtitle'] ?? null;
$record['organization'] = $properties['company'] ?? null;
}
$countryCode = $this->buildContactCountry($properties);
$parsedNumber = $this->buildContactPhone($countryCode, $properties);
// Add phone number to record.
if (! empty($parsedNumber['phone'])) {
$record['phoneNumbers'][] = [
'number' => $parsedNumber['phone'],
'nationalFormat' => phone_national($countryCode, $parsedNumber['phone']),
'type' => 'phone',
];
}
// Add mobile phone number to record.
if (! empty($properties['mobilephone'])) {
$mobileNumber = phone_e164($countryCode, $properties['mobilephone']);
if ($mobileNumber !== null) {
$record['phoneNumbers'][] = [
'number' => $mobileNumber,
'nationalFormat' => phone_national($countryCode, $mobileNumber),
'type' => 'mobile',
];
}
}
$data[] = $record;
}
} catch (BadRequest $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->getUuid(),
'request' => $payload,
'reason' => $e->getMessage(),
]);
throw $e;
}
}
return $data;
},
);
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
if ($crmAccountId === null) {
return $data;
}
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
$closedStages = $this->getClosedDealStages();
$payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(
$this->config,
$crmAccountId,
$closedStages,
);
$results = $this->client->getPaginatedData($payload, 'deals');
foreach ($results['results'] as $object) {
$properties = $object['properties'];
$amount = null;
if (empty($properties['amount']) === false) {
$currency = $properties['deal_currency_code'] ?? $this->config->default_currency;
// Values can contain commas and any junk so strip them.
$value = (float) preg_replace('/[^\d.]/', '', $properties['amount']);
$amount = formatCurrency($value, $currency);
}
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
if ($businessProcess === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
} else {
$stage = $businessProcess
->stages()
->where('crm_provider_id', $properties['dealstage'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages(null, $properties['dealstage']);
}
}
$recordType = null;
if ($businessProcess) {
$recordType = $businessProcess->recordTypes()->first();
}
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$record = [
'crmId' => $object['id'],
'name' => $properties['dealname'] ?? 'Unknown Deal',
'value' => $amount,
'won' => $isWon,
'closed' => $isWon || $isLost,
'stage' => [
'id' => $stage?->getUuid() ?? '',
'name' => $stage?->getName() ?? '',
],
];
if ($recordType) {
$record += [
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
}
if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array
{
$data = [];
switch ($objectType) {
case 'contact':
$hsObject = 'contact';
break;
case 'account':
$hsObject = 'company';
break;
default:
// This is a hack to prioritise and override a contact/company with a deal.
if ($opportunityId) {
$hsObject = 'deal';
$objectId = $opportunityId;
} else {
throw new InvalidArgumentException('Object type not supported.');
}
}
$engagementTypes = ['meetings', 'tasks'];
foreach ($engagementTypes as $engagementType) {
$payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);
$this->logger->info('[HubSpot] CRM Search requested', [
'request' => $payload,
]);
$engagements = $this->client->getPaginatedData($payload, $engagementType);
foreach ($engagements['results'] as $engagement) {
if ($engagementType == 'meetings') {
$title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';
} elseif ($engagementType == 'tasks') {
$title = $engagement['properties']['hs_task_subject'];
} else {
$title = 'Scheduled meeting';
}
$data[] = [
'crmId' => $engagement['id'],
'subject' => $title,
'due' => $engagement['properties']['hs_timestamp'],
'type' => $engagement['properties']['hs_activity_type'] ?? null,
];
}
}
usort($data, function ($item1, $item2) {
return $item2['due'] <=> $item1['due'];
});
return $data;
}
/**
* Try to find CRM Objects using email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$contactProperties = [
'email',
'firstname',
'lastname',
'country',
'phone',
'mobilephone',
'jobtitle',
'hubspot_owner_id',
'associatedcompanyid',
'photo',
];
$contact = null;
$account = null;
try {
$hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);
if ($hsContact) {
$contact = $this->importContact($hsContact);
$account = $contact->account;
}
$data = $this->convertCrmData($contact, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
} catch (BadRequest $e) {
$this->logger->warning('[HubSpot] Search failed', [
'team_id' => $this->team->getId(),
'search_identifier' => $email,
'reason' => $e->getMessage(),
]);
}
return null;
}
public function getDomain(string $email): ?string
{
return $this->getDomainFromEmail($email);
}
/**
* Try to find CRM objects using domain name of the email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByDomain(string $domain, ?int $userId = null): ?array
{
$companyName = $domain;
// Try to find a company matching their email domain.
$companyProperties = [
'country',
'phone',
'name',
'hs_avatar_filemanager_key',
'industry',
'hubspot_owner_id',
'domain',
];
try {
$hsAccounts = $this->client
->getInstance()
->companies()
->searchByDomain($companyName, $companyProperties);
} catch (Throwable $e) {
$this->logger->info('[HubSpot] Search failed', [
'error' => $e->getMessage(),
'domain' => $domain,
]);
return null;
}
$account = null;
// If there are multiple accounts, don't guess, we'll ask later.
if (\count($hsAccounts->data->results) === 1) {
// Persist this remote object.
$account = $this->syncAccount($hsAccounts->data->results[0]->companyId);
}
$data = $this->convertCrmData(null, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
}
/**
* @return array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array
{
$countryCode = null;
if ($contact && $contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account && $account->country_code) {
$countryCode = $account->country_code;
}
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
// If there are multiple opportunities, don't guess, we'll ask later.
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
if (str_contains($phone, '**')) {
return null;
}
// trim all whitespaces if present so the lookup doesn't fail
$phone = str_replace(' ', '', $phone);
// Check if the user is internal.
if ($this->isPhoneNumberOfTeamMember($phone)) {
return null;
}
$response = $this->searchForPhoneNumber($phone);
if (empty($response)) {
return null;
}
// This would ideally importContact instead but the response type differs.
$contact = $this->findAndSyncContact($response['results'][0]['id']);
if (! $contact instanceof Contact) {
return null;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
try {
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception $e) {
$this->logger->debug('[HubSpot] Opportunity failed to sync.', [
'reason' => $e->getMessage(),
]);
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
private function isPhoneNumberOfTeamMember(string $phone): bool
{
$teamRepository = app(TeamRepository::class);
$user = $teamRepository->findTeamMemberByPhone($this->team, $phone);
if ($user instanceof User) {
return true;
}
return false;
}
private function findAndSyncContact(string $crmId): ?Contact
{
try {
return $this->syncContact($crmId);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'reason' => $exception->getMessage(),
]);
return null;
}
}
private function hasResults(array $response): bool
{
return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;
}
private function searchForPhoneNumber(string $phone): array
{
// Normalizes the provided phone number for the API search.
$normalizedPhone = $this->normalizePhoneNumber($phone);
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);
$this->logger->info('[HubSpot] Phone match search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);
if (! $this->hasResults($response)) {
$nationalPhone = preg_replace('/\D/', '', phone_national(null, $phone));
$payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);
$this->logger->info('[HubSpot] Phone match national number search triggered', [
'phone' => $phone,
'nationalPhone' => $nationalPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
if (! $this->hasResults($response)) {
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);
$this->logger->info('[HubSpot] Phone match alternative search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
return $this->hasResults($response) ? $response : [];
}
private function handlePhoneSearchRequest(string $phone, array $payload): array
{
try {
return $this->client->search('contacts', $payload);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'phone' => $phone,
'reason' => $exception->getMessage(),
]);
return [];
}
}
private function normalizePhoneNumber(string $phone): string
{
return ltrim(phone_e164(null, $phone), '+0');
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$payload = $this->payloadBuilder->generateSearchContactsByNamePayload(
$name,
$this->getContactFields()
);
$hsContacts = $this->client->getPaginatedData($payload, 'contact');
if (empty($hsContacts['results'])) {
return false;
}
$contact = $this->importContact($hsContacts['results'][0]);
if ($contact === null) {
return false;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
});
return is_array($result) ? $result : null;
}
private function convertActivityAssociations(Activity $activity): array
{
return [
'contactIds' => $this->getParticipantsIds($activity),
'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],
'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],
'ownerIds' => [],
];
}
private function getParticipantsIds(Activity $activity): array
{
$attendees = [];
$participantRepository = app(ParticipantRepository::class);
$participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);
foreach ($participants as $participant) {
if ($participant->user_id || $participant->isCoach()) {
continue;
}
$contact = $participant->contact()->first();
if ($contact && $contact->crm_provider_id) {
$attendees[] = $contact->crm_provider_id;
} else {
if (! empty($participant->name)) {
$attendeeData = $this->fetchMissingAttendeeInfo($participant);
}
if (! empty($attendeeData['id'])) {
$attendees[] = $attendeeData['id'];
}
}
}
if ($activity->hasContact()) {
$attendees[] = $activity->contact->crm_provider_id;
}
return array_unique($attendees);
}
private function fetchMissingAttendeeInfo(Participant $participant): array
{
// Check if we need to look inside an account context.
$activity = $participant->getActivity();
$companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;
// First check the local data.
/** @var Contact[] $contacts */
$contacts = $this->team->contacts()
->with('account')
->where('name', $participant->name)
->whereNotNull('email')
->get();
foreach ($contacts as $contact) {
// If we have a company in scope, check the contact is associated to it.
if (
$companyId !== null
&& ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)
) {
continue;
}
return [
'id' => $contact->crm_provider_id,
'email' => $contact->email,
];
}
$payload = $this->generateNameSearchPayload($participant->name, 0, 20);
try {
$response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);
// TODO add some logic to choose the most suitable contact if multiple
foreach ($response['results'] as $object) {
$properties = $object['properties'];
if (empty($object['properties']) === false) {
// Check the company matches the contact.
// Todo: Move this check inside the API search.
if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {
continue;
}
return [
'id' => $object['id'],
'email' => $properties['email'],
];
}
}
} catch (Exception $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->id_string,
'request' => $payload,
'reason' => $e->getMessage(),
]);
}
return [];
}
/**
* Store transcripts as note engagement.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
// For HS no need to check if Crm profile - Log Notes field is enabled
// We only check if store_transcript toggle is enabled on crm profile.
$engagement = [
'active' => true,
'ownerId' => $this->profile->crm_provider_id,
'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,
'type' => 'NOTE',
];
// Generate activity transcription.
$transcriptionData = $this->generateTranscription($activity);
// Truncate Notes with max notes length because transcription text could be very long.
$transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);
$metadata = [
'body' => $transcripts,
];
$associations = $this->convertActivityAssociations($activity);
try {
$hsEngagement = $this->client
->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
$this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);
$noteId = $hsEngagement->data->engagement->id;
// Store crm logged id in transcription.
$transcription = $activity->getTranscription();
$transcription->crm_activity_id = $noteId;
$transcription->save();
} catch (Exception $e) {
Sentry::captureException($e);
}
}
/*
* @inheritdoc
*/
public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void
{
$payload = [
'properties' => $data,
];
try {
switch ($objectType) {
case FieldData::OBJECT_OPPORTUNITY:
$this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_CONTACT:
$this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_ACCOUNT:
$this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_TASK:
// Endpoint for Engagements not ready
$engagements = [
'type' => 'TASK',
];
$metadata = $data;
...
|
10163
|
NULL
|
NULL
|
NULL
|
|
10164
|
466
|
4
|
2026-05-08T17:06:54.967899+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260014967_m2.jpg...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Show Replace Field
Search History
doSearch
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/1
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Code changed:
Hide
Sync Changes
Hide This Notification
7
48
1
33
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Hubspot;
use Carbon\Carbon;
use Exception;
use Generator;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Cache;
use InvalidArgumentException;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\FetchRelatedActivityInterface;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SavePlaybackLinkToCrmInterface;
use Jiminny\Contracts\Services\Crm\SendSummaryToCrmInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Contracts\ActivityContract;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Participant;
use Jiminny\Models\Playbook;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\ParticipantRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Hubspot\Actions\SyncArchivedProfilesAction;
use Jiminny\Services\Crm\Hubspot\Fields\ValueNormalizer;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\OpportunitySyncTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncCrmEntitiesTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncFieldsTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\WriteCrmTrait;
use Jiminny\Services\Crm\MatchDomainByEmailInterface;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\ResolveCompanyNameByEmailTrait;
use Jiminny\Utils\PlaybackUrlBuilder;
use Sentry;
use SevenShores\Hubspot\Exceptions\BadRequest;
use Throwable;
use UnexpectedValueException;
/**
* @phpstan-type CrmFieldDefinition array{
* name: string,
* label: string,
* description: string,
* type: string,
* fieldType: string,
* hidden: bool,
* showCurrencySymbol: bool,
* options: array<array{
* id: string,
* label: string,
* value?: string,
* }
*/
class Service extends BaseService implements
HubspotInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
SendSummaryToCrmInterface,
MatchDomainByEmailInterface,
SavePlaybackLinkToCrmInterface,
RemoteEntityManipulationInterface,
FetchRelatedActivityInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use ResolveCompanyNameByEmailTrait;
use SyncCrmEntitiesTrait;
use WriteCrmTrait;
use SyncFieldsTrait;
use OpportunitySyncTrait;
private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;
private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';
private const int BATCH_UPDATE_LIMIT = 100;
private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';
private const int TEN_SECONDLY_ROLLING_LIMIT = 10;
private const string TYPE_NOTE = 'NOTE';
private const string TYPE_MEETING = 'MEETING';
private const string TYPE_CALL = 'CALL';
private const string API_URL = '[URL_WITH_CREDENTIALS] ClientInterface|Client
*/
protected $client;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected ProspectPhotoPathService $prospectPhotoPathService;
private SyncFieldAction $syncFieldAction;
private PayloadBuilder $payloadBuilder;
private SyncRelatedActivityManager $syncRelatedActivityManager;
private SyncArchivedProfilesAction $syncArchivedProfilesAction;
private WebhookSyncBatchProcessor $batchProcessor;
public function __construct(
Client $client,
SyncFieldAction $syncFieldAction,
PayloadBuilder $payloadBuilder,
ProspectPhotoPathService $prospectPhotoPathService,
SyncArchivedProfilesAction $syncArchivedProfilesAction,
WebhookSyncBatchProcessor $batchProcessor,
) {
parent::__construct();
$this->client = $client;
$this->syncFieldAction = $syncFieldAction;
$this->prospectPhotoPathService = $prospectPhotoPathService;
$this->payloadBuilder = $payloadBuilder;
$this->syncArchivedProfilesAction = $syncArchivedProfilesAction;
$this->batchProcessor = $batchProcessor;
$this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [
'client' => $this->client,
'payloadBuilder' => $this->payloadBuilder,
'logger' => $this->logger,
]);
$this->crmEntityRepository = app(CrmEntityRepository::class);
$this->dealFieldsService = app(DealFieldsService::class);
}
public function getDisplayName(): string
{
return 'HubSpot';
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);
}
public function getClient(): Client
{
/** @var Client */
return $this->client;
}
/**
* Convert raw field data into a format compatible with CRM APIs.
*
* @param bool $internal Direction of the conversion.
* True is pulling from CRM, false normalize before sending to CRM.
*/
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return ValueNormalizer::normalize(
fieldType: $fieldType,
fieldValue: $fieldValue,
isInbound: $internal,
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'activityType',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
/**
* @inheritdoc
*/
public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
// Outcome should always be provided calls/meetings.
$fieldData = [
[
'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',
'object_type' => Field::OBJECT_TASK,
],
];
foreach ($fieldData as $data) {
$field = $this->config->fields()->where($data)->first();
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
}
return $fields;
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function syncField(Field $field): void
{
switch ($field->object_type) {
case Field::OBJECT_ACCOUNT:
$crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_CONTACT:
$crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_OPPORTUNITY:
$crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_TASK:
$this->syncSingleTaskField($field);
return;
default:
return;
}
$this->syncFieldAction->execute($field, $crmField->toArray());
}
/**
* @param array<array{
* id:string,
* label:string,
* value?:string
* }> $options
*
* @throws CrmException
*
* @return FieldData[]
*
*/
public function importPicklistValues(
Field $field,
array $options = [['id' => '', 'label' => '', 'value' => '']],
): array {
if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {
// We already have the options, no need to fetch them again
return $this->importOptions($field, $options);
}
$options = [];
switch ($field->getObjectType()) {
case Field::OBJECT_ACCOUNT:
$options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());
break;
case Field::OBJECT_CONTACT:
$options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());
break;
case Field::OBJECT_OPPORTUNITY:
// Hubspot has different endpoint for stages
$options = $this->getClient()->fetchOpportunityFieldOptions($field);
break;
case Field::OBJECT_TASK:
if ($field->getCrmProviderId() === 'disposition') {
$options = $this->getClient()->fetchDispositionFieldOptions();
} elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {
$options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);
}
break;
default:
$this->logger->warning('Invalid object type', [
'object_type' => $field->getObjectType(),
'field_id' => $field->getId(),
]);
throw new CrmException('Invalid object type');
}
return $this->importOptions($field, $options);
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
$missingStage = null;
try {
// Use the HubSpot API client instead of the SDK crmPipelines() method
$endpoint = self::getDealsPipelinesEndpoint();
$pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);
$pipelines = $pipelinesResponse->data->results;
} catch (RequestException|BadRequest $exception) {
throw $exception;
}
foreach ($pipelines as $pipeline) {
$stages = [];
// We create a business process to contain the pipeline, and store all stages against it.
$p = ResponseNormalize::normalizePipeline($pipeline);
// Create/update business process for this pipeline
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => $p['active'],
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
// Create/update record type clone
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'is_selectable' => $p['active'],
'business_process_id' => $businessProcess->id ?? null,
]);
// Stages - fetch all existing stages upfront to avoid N+1 queries
$existingStages = $this->config->stages()
->withTrashed()
->where('type', Stage::TYPE_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
foreach ($p['stages'] as $dealStage) {
$s = ResponseNormalize::normalizeDealStage($dealStage);
/** @var ?Stage $existingStage */
$existingStage = $existingStages->get($s['id']);
// Restore soft-deleted stages that are now active in HubSpot
if ($existingStage?->trashed() && $s['active']) {
$existingStage->restore();
}
// Upsert stage (updates soft-deleted records without restoring them)
$stage = $this->config->stages()->withTrashed()->updateOrCreate([
'crm_provider_id' => $s['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($s['label'], 0, 50),
'label' => mb_strimwidth($s['label'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $s['displayOrder'],
'is_selectable' => $s['active'],
'probability' => $s['probability'] * 100,
]);
if ($missingStageName === $s['id']) {
$missingStage = $stage;
}
$stages[] = $stage->id;
}
$businessProcess->stages()->sync($stages);
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
try {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
/** @var array<int, array<string, mixed>> */
return Cache::remember(
key: $this->team->getId() . $name . $count . $offset,
ttl: 300,
callback: function () use ($name, $offset, $count): array {
$data = [];
// Use the new V3 API to find contacts based on additional fields.
foreach (['companies', 'contacts'] as $objectType) {
$payload = $this->generateNameSearchPayload($name, $offset, $count);
$type = $objectType === 'companies' ? 'account' : 'contact';
try {
$response = $this->client->search($objectType, $payload);
// Build mapped list.
foreach ($response['results'] as $object) {
$properties = $object['properties'];
$objectName = $this->buildContactName($properties);
$record = [
'crmId' => $object['id'],
// Pass crmUrl to the FE, needed for success message in the extension when you log activity.
'crmUrl' => $this->generateProviderUrl($object['id'], $type),
'name' => $objectName,
'prospectType' => $type,
'phoneNumbers' => [],
];
if ($type === 'account') {
$record['industry'] = $properties['industry'] ?? null;
} else {
$record['title'] = $properties['jobtitle'] ?? null;
$record['organization'] = $properties['company'] ?? null;
}
$countryCode = $this->buildContactCountry($properties);
$parsedNumber = $this->buildContactPhone($countryCode, $properties);
// Add phone number to record.
if (! empty($parsedNumber['phone'])) {
$record['phoneNumbers'][] = [
'number' => $parsedNumber['phone'],
'nationalFormat' => phone_national($countryCode, $parsedNumber['phone']),
'type' => 'phone',
];
}
// Add mobile phone number to record.
if (! empty($properties['mobilephone'])) {
$mobileNumber = phone_e164($countryCode, $properties['mobilephone']);
if ($mobileNumber !== null) {
$record['phoneNumbers'][] = [
'number' => $mobileNumber,
'nationalFormat' => phone_national($countryCode, $mobileNumber),
'type' => 'mobile',
];
}
}
$data[] = $record;
}
} catch (BadRequest $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->getUuid(),
'request' => $payload,
'reason' => $e->getMessage(),
]);
throw $e;
}
}
return $data;
},
);
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
if ($crmAccountId === null) {
return $data;
}
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
$closedStages = $this->getClosedDealStages();
$payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(
$this->config,
$crmAccountId,
$closedStages,
);
$results = $this->client->getPaginatedData($payload, 'deals');
foreach ($results['results'] as $object) {
$properties = $object['properties'];
$amount = null;
if (empty($properties['amount']) === false) {
$currency = $properties['deal_currency_code'] ?? $this->config->default_currency;
// Values can contain commas and any junk so strip them.
$value = (float) preg_replace('/[^\d.]/', '', $properties['amount']);
$amount = formatCurrency($value, $currency);
}
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
if ($businessProcess === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
} else {
$stage = $businessProcess
->stages()
->where('crm_provider_id', $properties['dealstage'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages(null, $properties['dealstage']);
}
}
$recordType = null;
if ($businessProcess) {
$recordType = $businessProcess->recordTypes()->first();
}
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$record = [
'crmId' => $object['id'],
'name' => $properties['dealname'] ?? 'Unknown Deal',
'value' => $amount,
'won' => $isWon,
'closed' => $isWon || $isLost,
'stage' => [
'id' => $stage?->getUuid() ?? '',
'name' => $stage?->getName() ?? '',
],
];
if ($recordType) {
$record += [
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
}
if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array
{
$data = [];
switch ($objectType) {
case 'contact':
$hsObject = 'contact';
break;
case 'account':
$hsObject = 'company';
break;
default:
// This is a hack to prioritise and override a contact/company with a deal.
if ($opportunityId) {
$hsObject = 'deal';
$objectId = $opportunityId;
} else {
throw new InvalidArgumentException('Object type not supported.');
}
}
$engagementTypes = ['meetings', 'tasks'];
foreach ($engagementTypes as $engagementType) {
$payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);
$this->logger->info('[HubSpot] CRM Search requested', [
'request' => $payload,
]);
$engagements = $this->client->getPaginatedData($payload, $engagementType);
foreach ($engagements['results'] as $engagement) {
if ($engagementType == 'meetings') {
$title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';
} elseif ($engagementType == 'tasks') {
$title = $engagement['properties']['hs_task_subject'];
} else {
$title = 'Scheduled meeting';
}
$data[] = [
'crmId' => $engagement['id'],
'subject' => $title,
'due' => $engagement['properties']['hs_timestamp'],
'type' => $engagement['properties']['hs_activity_type'] ?? null,
];
}
}
usort($data, function ($item1, $item2) {
return $item2['due'] <=> $item1['due'];
});
return $data;
}
/**
* Try to find CRM Objects using email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$contactProperties = [
'email',
'firstname',
'lastname',
'country',
'phone',
'mobilephone',
'jobtitle',
'hubspot_owner_id',
'associatedcompanyid',
'photo',
];
$contact = null;
$account = null;
try {
$hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);
if ($hsContact) {
$contact = $this->importContact($hsContact);
$account = $contact->account;
}
$data = $this->convertCrmData($contact, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
} catch (BadRequest $e) {
$this->logger->warning('[HubSpot] Search failed', [
'team_id' => $this->team->getId(),
'search_identifier' => $email,
'reason' => $e->getMessage(),
]);
}
return null;
}
public function getDomain(string $email): ?string
{
return $this->getDomainFromEmail($email);
}
/**
* Try to find CRM objects using domain name of the email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByDomain(string $domain, ?int $userId = null): ?array
{
$companyName = $domain;
// Try to find a company matching their email domain.
$companyProperties = [
'country',
'phone',
'name',
'hs_avatar_filemanager_key',
'industry',
'hubspot_owner_id',
'domain',
];
try {
$hsAccounts = $this->client
->getInstance()
->companies()
->searchByDomain($companyName, $companyProperties);
} catch (Throwable $e) {
$this->logger->info('[HubSpot] Search failed', [
'error' => $e->getMessage(),
'domain' => $domain,
]);
return null;
}
$account = null;
// If there are multiple accounts, don't guess, we'll ask later.
if (\count($hsAccounts->data->results) === 1) {
// Persist this remote object.
$account = $this->syncAccount($hsAccounts->data->results[0]->companyId);
}
$data = $this->convertCrmData(null, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
}
/**
* @return array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array
{
$countryCode = null;
if ($contact && $contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account && $account->country_code) {
$countryCode = $account->country_code;
}
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
// If there are multiple opportunities, don't guess, we'll ask later.
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
if (str_contains($phone, '**')) {
return null;
}
// trim all whitespaces if present so the lookup doesn't fail
$phone = str_replace(' ', '', $phone);
// Check if the user is internal.
if ($this->isPhoneNumberOfTeamMember($phone)) {
return null;
}
$response = $this->searchForPhoneNumber($phone);
if (empty($response)) {
return null;
}
// This would ideally importContact instead but the response type differs.
$contact = $this->findAndSyncContact($response['results'][0]['id']);
if (! $contact instanceof Contact) {
return null;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
try {
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception $e) {
$this->logger->debug('[HubSpot] Opportunity failed to sync.', [
'reason' => $e->getMessage(),
]);
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
private function isPhoneNumberOfTeamMember(string $phone): bool
{
$teamRepository = app(TeamRepository::class);
$user = $teamRepository->findTeamMemberByPhone($this->team, $phone);
if ($user instanceof User) {
return true;
}
return false;
}
private function findAndSyncContact(string $crmId): ?Contact
{
try {
return $this->syncContact($crmId);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'reason' => $exception->getMessage(),
]);
return null;
}
}
private function hasResults(array $response): bool
{
return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;
}
private function searchForPhoneNumber(string $phone): array
{
// Normalizes the provided phone number for the API search.
$normalizedPhone = $this->normalizePhoneNumber($phone);
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);
$this->logger->info('[HubSpot] Phone match search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);
if (! $this->hasResults($response)) {
$nationalPhone = preg_replace('/\D/', '', phone_national(null, $phone));
$payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);
$this->logger->info('[HubSpot] Phone match national number search triggered', [
'phone' => $phone,
'nationalPhone' => $nationalPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
if (! $this->hasResults($response)) {
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);
$this->logger->info('[HubSpot] Phone match alternative search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
return $this->hasResults($response) ? $response : [];
}
private function handlePhoneSearchRequest(string $phone, array $payload): array
{
try {
return $this->client->search('contacts', $payload);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'phone' => $phone,
'reason' => $exception->getMessage(),
]);
return [];
}
}
private function normalizePhoneNumber(string $phone): string
{
return ltrim(phone_e164(null, $phone), '+0');
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$payload = $this->payloadBuilder->generateSearchContactsByNamePayload(
$name,
$this->getContactFields()
);
$hsContacts = $this->client->getPaginatedData($payload, 'contact');
if (empty($hsContacts['results'])) {
return false;
}
$contact = $this->importContact($hsContacts['results'][0]);
if ($contact === null) {
return false;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
});
return is_array($result) ? $result : null;
}
private function convertActivityAssociations(Activity $activity): array
{
return [
'contactIds' => $this->getParticipantsIds($activity),
'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],
'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],
'ownerIds' => [],
];
}
private function getParticipantsIds(Activity $activity): array
{
$attendees = [];
$participantRepository = app(ParticipantRepository::class);
$participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);
foreach ($participants as $participant) {
if ($participant->user_id || $participant->isCoach()) {
continue;
}
$contact = $participant->contact()->first();
if ($contact && $contact->crm_provider_id) {
$attendees[] = $contact->crm_provider_id;
} else {
if (! empty($participant->name)) {
$attendeeData = $this->fetchMissingAttendeeInfo($participant);
}
if (! empty($attendeeData['id'])) {
$attendees[] = $attendeeData['id'];
}
}
}
if ($activity->hasContact()) {
$attendees[] = $activity->contact->crm_provider_id;
}
return array_unique($attendees);
}
private function fetchMissingAttendeeInfo(Participant $participant): array
{
// Check if we need to look inside an account context.
$activity = $participant->getActivity();
$companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;
// First check the local data.
/** @var Contact[] $contacts */
$contacts = $this->team->contacts()
->with('account')
->where('name', $participant->name)
->whereNotNull('email')
->get();
foreach ($contacts as $contact) {
// If we have a company in scope, check the contact is associated to it.
if (
$companyId !== null
&& ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)
) {
continue;
}
return [
'id' => $contact->crm_provider_id,
'email' => $contact->email,
];
}
$payload = $this->generateNameSearchPayload($participant->name, 0, 20);
try {
$response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);
// TODO add some logic to choose the most suitable contact if multiple
foreach ($response['results'] as $object) {
$properties = $object['properties'];
if (empty($object['properties']) === false) {
// Check the company matches the contact.
// Todo: Move this check inside the API search.
if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {
continue;
}
return [
'id' => $object['id'],
'email' => $properties['email'],
];
}
}
} catch (Exception $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->id_string,
'request' => $payload,
'reason' => $e->getMessage(),
]);
}
return [];
}
/**
* Store transcripts as note engagement.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
// For HS no need to check if Crm profile - Log Notes field is enabled
// We only check if store_transcript toggle is enabled on crm profile.
$engagement = [
'active' => true,
'ownerId' => $this->profile->crm_provider_id,
'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,
'type' => 'NOTE',
];
// Generate activity transcription.
$transcriptionData = $this->generateTranscription($activity);
// Truncate Notes with max notes length because transcription text could be very long.
$transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);
$metadata = [
'body' => $transcripts,
];
$associations = $this->convertActivityAssociations($activity);
try {
$hsEngagement = $this->client
->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
$this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);
$noteId = $hsEngagement->data->engagement->id;
// Store crm logged id in transcription.
$transcription = $activity->getTranscription();
$transcription->crm_activity_id = $noteId;
$transcription->save();
} catch (Exception $e) {
Sentry::captureException($e);
}
}
/*
* @inheritdoc
*/
public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void
{
$payload = [
'properties' => $data,
];
try {
switch ($objectType) {
case FieldData::OBJECT_OPPORTUNITY:
$this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_CONTACT:
$this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_ACCOUNT:
$this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_TASK:
// Endpoint for Engagements not ready
$engagements = [
'type' => 'TASK',
];
$metadata = $data;
...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.6296542,"top":0.10055866,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.6409575,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.64827126,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"bounds":{"left":0.43018618,"top":0.09736632,"width":0.56981385,"height":0.8818835},"on_screen":true,"lines":[{"char_start":207,"char_count":30,"bounds":{"left":0.43018618,"top":0.0,"width":0.07513298,"height":0.014365523}},{"char_start":237,"char_count":36,"bounds":{"left":0.43018618,"top":0.0,"width":0.09075798,"height":0.014365523}},{"char_start":273,"char_count":32,"bounds":{"left":0.43018618,"top":0.0,"width":0.080119684,"height":0.014365523}},{"char_start":305,"char_count":79,"bounds":{"left":0.43018618,"top":0.0,"width":0.20212767,"height":0.014365523}},{"char_start":384,"char_count":18,"bounds":{"left":0.43018618,"top":0.0,"width":0.043882977,"height":0.014365523}},{"char_start":402,"char_count":21,"bounds":{"left":0.43018618,"top":0.0,"width":0.051861703,"height":0.014365523}},{"char_start":423,"char_count":48,"bounds":{"left":0.43018618,"top":0.008778931,"width":0.12167553,"height":0.014365523}},{"char_start":471,"char_count":72,"bounds":{"left":0.43018618,"top":0.026336791,"width":0.18384309,"height":0.014365523}},{"char_start":543,"char_count":40,"bounds":{"left":0.43018618,"top":0.043894652,"width":0.10106383,"height":0.014365523}},{"char_start":583,"char_count":41,"bounds":{"left":0.43018618,"top":0.061452515,"width":0.10372341,"height":0.014365523}},{"char_start":624,"char_count":72,"bounds":{"left":0.43018618,"top":0.079010375,"width":0.18384309,"height":0.014365523}},{"char_start":696,"char_count":219,"bounds":{"left":0.43018618,"top":0.096568234,"width":0.56515956,"height":0.014365523}},{"char_start":915,"char_count":83,"bounds":{"left":0.43018618,"top":0.11412609,"width":0.21243352,"height":0.014365523}},{"char_start":998,"char_count":20,"bounds":{"left":0.43018618,"top":0.13168396,"width":0.04920213,"height":0.014365523}},{"char_start":1018,"char_count":17,"bounds":{"left":0.43018618,"top":0.14924182,"width":0.041223403,"height":0.014365523}},{"char_start":1035,"char_count":203,"bounds":{"left":0.43018618,"top":0.16679968,"width":0.52360374,"height":0.014365523}},{"char_start":1238,"char_count":22,"bounds":{"left":0.43018618,"top":0.18435754,"width":0.05418883,"height":0.014365523}},{"char_start":1260,"char_count":23,"bounds":{"left":0.43018618,"top":0.2019154,"width":0.056848403,"height":0.014365523}},{"char_start":1283,"char_count":10,"bounds":{"left":0.43018618,"top":0.21947326,"width":0.023271276,"height":0.014365523}},{"char_start":1293,"char_count":27,"bounds":{"left":0.43018618,"top":0.23703113,"width":0.06715426,"height":0.014365523}},{"char_start":1320,"char_count":26,"bounds":{"left":0.43018618,"top":0.254589,"width":0.06482713,"height":0.014365523}},{"char_start":1346,"char_count":23,"bounds":{"left":0.43018618,"top":0.27214685,"width":0.056848403,"height":0.014365523}},{"char_start":1369,"char_count":28,"bounds":{"left":0.43018618,"top":0.2897047,"width":0.06981383,"height":0.014365523}},{"char_start":1397,"char_count":57,"bounds":{"left":0.43018618,"top":0.30726257,"width":0.14494681,"height":0.014365523}}],"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Replace Field","depth":4,"bounds":{"left":0.10472074,"top":0.17956904,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Search History","depth":3,"bounds":{"left":0.11735372,"top":0.17877094,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"doSearch","depth":4,"bounds":{"left":0.12832446,"top":0.17877094,"width":0.043882977,"height":0.015961692},"on_screen":true,"value":"doSearch","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"bounds":{"left":0.18118352,"top":0.17877094,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Match Case","depth":3,"bounds":{"left":0.19115691,"top":0.17877094,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Words","depth":3,"bounds":{"left":0.19980054,"top":0.17877094,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Regex","depth":3,"bounds":{"left":0.20844415,"top":0.17877094,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Replace History","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Replace","depth":4,"on_screen":false,"role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Preserve case","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1/1","depth":4,"bounds":{"left":0.22207446,"top":0.17797287,"width":0.025598405,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Occurrence","depth":4,"bounds":{"left":0.24767287,"top":0.17717478,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Occurrence","depth":4,"bounds":{"left":0.25631648,"top":0.17717478,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Filter Search Results","depth":4,"bounds":{"left":0.2649601,"top":0.17717478,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Window, Multiple Cursors","depth":4,"bounds":{"left":0.27360374,"top":0.17717478,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Click to highlight","depth":4,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":4,"bounds":{"left":0.39793882,"top":0.17717478,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"7","depth":4,"bounds":{"left":0.34408244,"top":0.20830008,"width":0.0076462766,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"48","depth":4,"bounds":{"left":0.3537234,"top":0.20830008,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.36602393,"top":0.20830008,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"33","depth":4,"bounds":{"left":0.37533244,"top":0.20830008,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.38763297,"top":0.20830008,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39660904,"top":0.20670392,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.4039229,"top":0.20670392,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse Generator;\nuse GuzzleHttp\\Exception\\RequestException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse InvalidArgumentException;\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Contracts\\Services\\Crm\\ClientInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\FetchRelatedActivityInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\HubspotInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SavePlaybackLinkToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SendSummaryToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Contracts\\ActivityContract;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\Layout;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Participant;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\ParticipantRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Hubspot\\Actions\\SyncArchivedProfilesAction;\nuse Jiminny\\Services\\Crm\\Hubspot\\Fields\\ValueNormalizer;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\OpportunitySyncTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncCrmEntitiesTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncFieldsTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\WriteCrmTrait;\nuse Jiminny\\Services\\Crm\\MatchDomainByEmailInterface;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\ResolveCompanyNameByEmailTrait;\nuse Jiminny\\Utils\\PlaybackUrlBuilder;\nuse Sentry;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse Throwable;\nuse UnexpectedValueException;\n\n/**\n * @phpstan-type CrmFieldDefinition array{\n * name: string,\n * label: string,\n * description: string,\n * type: string,\n * fieldType: string,\n * hidden: bool,\n * showCurrencySymbol: bool,\n * options: array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }\n */\nclass Service extends BaseService implements\n HubspotInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n SendSummaryToCrmInterface,\n MatchDomainByEmailInterface,\n SavePlaybackLinkToCrmInterface,\n RemoteEntityManipulationInterface,\n FetchRelatedActivityInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use ResolveCompanyNameByEmailTrait;\n use SyncCrmEntitiesTrait;\n use WriteCrmTrait;\n use SyncFieldsTrait;\n use OpportunitySyncTrait;\n\n private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;\n\n private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';\n private const int BATCH_UPDATE_LIMIT = 100;\n private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';\n private const int TEN_SECONDLY_ROLLING_LIMIT = 10;\n\n private const string TYPE_NOTE = 'NOTE';\n\n private const string TYPE_MEETING = 'MEETING';\n\n private const string TYPE_CALL = 'CALL';\n\n private const string API_URL = 'https://api.hubapi.com';\n\n // NB: v1 is legacy - v3 is the newest\n private const string ENDPOINT_PIPELINES = '/crm-pipelines/v1/pipelines/';\n private const string PIPELINE_OBJECT_TYPE_DEALS = 'deals';\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n /**\n * @var ClientInterface|Client\n */\n protected $client;\n protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;\n protected CrmEntityRepository $crmEntityRepository;\n protected ProspectPhotoPathService $prospectPhotoPathService;\n\n private SyncFieldAction $syncFieldAction;\n private PayloadBuilder $payloadBuilder;\n private SyncRelatedActivityManager $syncRelatedActivityManager;\n private SyncArchivedProfilesAction $syncArchivedProfilesAction;\n private WebhookSyncBatchProcessor $batchProcessor;\n\n public function __construct(\n Client $client,\n SyncFieldAction $syncFieldAction,\n PayloadBuilder $payloadBuilder,\n ProspectPhotoPathService $prospectPhotoPathService,\n SyncArchivedProfilesAction $syncArchivedProfilesAction,\n WebhookSyncBatchProcessor $batchProcessor,\n ) {\n parent::__construct();\n\n $this->client = $client;\n $this->syncFieldAction = $syncFieldAction;\n $this->prospectPhotoPathService = $prospectPhotoPathService;\n $this->payloadBuilder = $payloadBuilder;\n $this->syncArchivedProfilesAction = $syncArchivedProfilesAction;\n $this->batchProcessor = $batchProcessor;\n $this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->client,\n ]);\n $this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [\n 'client' => $this->client,\n 'payloadBuilder' => $this->payloadBuilder,\n 'logger' => $this->logger,\n ]);\n $this->crmEntityRepository = app(CrmEntityRepository::class);\n $this->dealFieldsService = app(DealFieldsService::class);\n }\n\n public function getDisplayName(): string\n {\n return 'HubSpot';\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);\n }\n\n public function getClient(): Client\n {\n /** @var Client */\n return $this->client;\n }\n\n /**\n * Convert raw field data into a format compatible with CRM APIs.\n *\n * @param bool $internal Direction of the conversion.\n * True is pulling from CRM, false normalize before sending to CRM.\n */\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return ValueNormalizer::normalize(\n fieldType: $fieldType,\n fieldValue: $fieldValue,\n isInbound: $internal,\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n /** @var Field $activityField */\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'activityType',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n // Outcome should always be provided calls/meetings.\n $fieldData = [\n [\n 'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',\n 'object_type' => Field::OBJECT_TASK,\n ],\n ];\n\n foreach ($fieldData as $data) {\n $field = $this->config->fields()->where($data)->first();\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n }\n\n return $fields;\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldData = FieldDefinitions::followupFieldsFilter();\n\n foreach ($fieldData as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function syncField(Field $field): void\n {\n switch ($field->object_type) {\n case Field::OBJECT_ACCOUNT:\n $crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_CONTACT:\n $crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_OPPORTUNITY:\n $crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_TASK:\n $this->syncSingleTaskField($field);\n\n return;\n default:\n return;\n }\n\n $this->syncFieldAction->execute($field, $crmField->toArray());\n }\n\n /**\n * @param array<array{\n * id:string,\n * label:string,\n * value?:string\n * }> $options\n *\n * @throws CrmException\n *\n * @return FieldData[]\n *\n */\n public function importPicklistValues(\n Field $field,\n array $options = [['id' => '', 'label' => '', 'value' => '']],\n ): array {\n if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {\n // We already have the options, no need to fetch them again\n return $this->importOptions($field, $options);\n }\n\n $options = [];\n\n switch ($field->getObjectType()) {\n case Field::OBJECT_ACCOUNT:\n $options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_CONTACT:\n $options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_OPPORTUNITY:\n // Hubspot has different endpoint for stages\n $options = $this->getClient()->fetchOpportunityFieldOptions($field);\n\n break;\n\n case Field::OBJECT_TASK:\n if ($field->getCrmProviderId() === 'disposition') {\n $options = $this->getClient()->fetchDispositionFieldOptions();\n } elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {\n $options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);\n }\n\n break;\n\n default:\n $this->logger->warning('Invalid object type', [\n 'object_type' => $field->getObjectType(),\n 'field_id' => $field->getId(),\n ]);\n\n throw new CrmException('Invalid object type');\n }\n\n return $this->importOptions($field, $options);\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n $missingStage = null;\n\n try {\n // Use the HubSpot API client instead of the SDK crmPipelines() method\n $endpoint = self::getDealsPipelinesEndpoint();\n $pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);\n $pipelines = $pipelinesResponse->data->results;\n } catch (RequestException|BadRequest $exception) {\n throw $exception;\n }\n\n foreach ($pipelines as $pipeline) {\n $stages = [];\n\n // We create a business process to contain the pipeline, and store all stages against it.\n $p = ResponseNormalize::normalizePipeline($pipeline);\n\n // Create/update business process for this pipeline\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => $p['active'],\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n // Create/update record type clone\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'is_selectable' => $p['active'],\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n // Stages - fetch all existing stages upfront to avoid N+1 queries\n $existingStages = $this->config->stages()\n ->withTrashed()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get()\n ->keyBy('crm_provider_id');\n\n foreach ($p['stages'] as $dealStage) {\n $s = ResponseNormalize::normalizeDealStage($dealStage);\n\n /** @var ?Stage $existingStage */\n $existingStage = $existingStages->get($s['id']);\n\n // Restore soft-deleted stages that are now active in HubSpot\n if ($existingStage?->trashed() && $s['active']) {\n $existingStage->restore();\n }\n\n // Upsert stage (updates soft-deleted records without restoring them)\n $stage = $this->config->stages()->withTrashed()->updateOrCreate([\n 'crm_provider_id' => $s['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($s['label'], 0, 50),\n 'label' => mb_strimwidth($s['label'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $s['displayOrder'],\n 'is_selectable' => $s['active'],\n 'probability' => $s['probability'] * 100,\n ]);\n\n if ($missingStageName === $s['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage->id;\n }\n\n $businessProcess->stages()->sync($stages);\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n try {\n $endpoint = 'https://api.hubapi.com/integrations/v1/me';\n $response = $this->client->getInstance()->getClient()->request('get', $endpoint);\n\n $accountData = $response->data;\n $this->config->update(['default_currency' => $accountData->currency]);\n } catch (BadRequest $e) {\n throw new CrmException('Could not sync the organization.', $e->getCode(), $e);\n }\n }\n\n /**\n * @inheritdoc\n *\n * @throws CrmException\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $this->syncArchivedProfilesAction->execute($this->team, $this->client, $this->config);\n\n try {\n $owners = $this->client->getOwners();\n } catch (\\HubSpot\\Client\\Crm\\Owners\\ApiException $e) {\n $this->logger->error('[HubSpot] Could not sync the profiles.', [\n 'team_id' => $this->team->getId(),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new CrmException('Could not sync the profiles.', $e->getCode(), $e);\n }\n\n $profileRepository = app(ProfileRepository::class);\n $teamRepository = app(TeamRepository::class);\n\n foreach ($owners as $owner) {\n if ($owner->getArchived()) {\n // not supposed to fetch archived, but log anyway\n $this->logger->warning('[HubSpot] Found archived owner', [\n 'crm_provider_id' => $owner->getId(),\n 'email' => $owner->getEmail(),\n ]);\n\n continue;\n }\n\n $email = $owner->getEmail();\n if ($email === null) {\n continue;\n }\n\n $user = $teamRepository->findActiveTeamMemberByEmail($this->team, $email);\n\n if (! $user instanceof User) {\n continue;\n }\n\n $profile = $profileRepository->updateOrCreateProfile($user, [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $owner->getId(),\n ]);\n\n if ($userToSearch && $userToSearch->getId() === $user->getId()) {\n return $profile;\n }\n }\n\n return null;\n }\n\n private function generateNameSearchPayload(string $name, int $offset, int $limit): array\n {\n $payload = [\n 'query' => $name,\n 'sorts' => [\n [\n 'propertyName' => 'modifieddate',\n 'direction' => 'DESCENDING',\n ],\n ],\n 'properties' => [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n 'industry',\n 'name',\n 'company',\n ],\n 'limit' => $limit,\n 'after' => $offset,\n ];\n\n $this->logger->debug('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n return $payload;\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n /** @var array<int, array<string, mixed>> */\n return Cache::remember(\n key: $this->team->getId() . $name . $count . $offset,\n ttl: 300,\n callback: function () use ($name, $offset, $count): array {\n $data = [];\n\n // Use the new V3 API to find contacts based on additional fields.\n foreach (['companies', 'contacts'] as $objectType) {\n $payload = $this->generateNameSearchPayload($name, $offset, $count);\n $type = $objectType === 'companies' ? 'account' : 'contact';\n\n try {\n $response = $this->client->search($objectType, $payload);\n\n // Build mapped list.\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n\n $objectName = $this->buildContactName($properties);\n\n $record = [\n 'crmId' => $object['id'],\n // Pass crmUrl to the FE, needed for success message in the extension when you log activity.\n 'crmUrl' => $this->generateProviderUrl($object['id'], $type),\n 'name' => $objectName,\n 'prospectType' => $type,\n 'phoneNumbers' => [],\n ];\n\n if ($type === 'account') {\n $record['industry'] = $properties['industry'] ?? null;\n } else {\n $record['title'] = $properties['jobtitle'] ?? null;\n $record['organization'] = $properties['company'] ?? null;\n }\n\n $countryCode = $this->buildContactCountry($properties);\n $parsedNumber = $this->buildContactPhone($countryCode, $properties);\n\n // Add phone number to record.\n if (! empty($parsedNumber['phone'])) {\n $record['phoneNumbers'][] = [\n 'number' => $parsedNumber['phone'],\n 'nationalFormat' => phone_national($countryCode, $parsedNumber['phone']),\n 'type' => 'phone',\n ];\n }\n\n // Add mobile phone number to record.\n if (! empty($properties['mobilephone'])) {\n $mobileNumber = phone_e164($countryCode, $properties['mobilephone']);\n if ($mobileNumber !== null) {\n $record['phoneNumbers'][] = [\n 'number' => $mobileNumber,\n 'nationalFormat' => phone_national($countryCode, $mobileNumber),\n 'type' => 'mobile',\n ];\n }\n }\n\n $data[] = $record;\n }\n } catch (BadRequest $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->getUuid(),\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n }\n\n return $data;\n },\n );\n }\n\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n\n if ($crmAccountId === null) {\n return $data;\n }\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n $closedStages = $this->getClosedDealStages();\n $payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(\n $this->config,\n $crmAccountId,\n $closedStages,\n );\n\n $results = $this->client->getPaginatedData($payload, 'deals');\n\n foreach ($results['results'] as $object) {\n $properties = $object['properties'];\n\n $amount = null;\n if (empty($properties['amount']) === false) {\n $currency = $properties['deal_currency_code'] ?? $this->config->default_currency;\n\n // Values can contain commas and any junk so strip them.\n $value = (float) preg_replace('/[^\\d.]/', '', $properties['amount']);\n $amount = formatCurrency($value, $currency);\n }\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n } else {\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', $properties['dealstage'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages(null, $properties['dealstage']);\n }\n }\n\n $recordType = null;\n if ($businessProcess) {\n $recordType = $businessProcess->recordTypes()->first();\n }\n\n $isWon = in_array($properties['dealstage'], $closedStages['won']);\n $isLost = in_array($properties['dealstage'], $closedStages['lost']);\n\n $record = [\n 'crmId' => $object['id'],\n 'name' => $properties['dealname'] ?? 'Unknown Deal',\n 'value' => $amount,\n 'won' => $isWon,\n 'closed' => $isWon || $isLost,\n 'stage' => [\n 'id' => $stage?->getUuid() ?? '',\n 'name' => $stage?->getName() ?? '',\n ],\n ];\n\n if ($recordType) {\n $record += [\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n }\n\n if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = [];\n switch ($objectType) {\n case 'contact':\n $hsObject = 'contact';\n\n break;\n case 'account':\n $hsObject = 'company';\n\n break;\n default:\n // This is a hack to prioritise and override a contact/company with a deal.\n if ($opportunityId) {\n $hsObject = 'deal';\n $objectId = $opportunityId;\n } else {\n throw new InvalidArgumentException('Object type not supported.');\n }\n }\n\n $engagementTypes = ['meetings', 'tasks'];\n\n foreach ($engagementTypes as $engagementType) {\n $payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);\n\n $this->logger->info('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n $engagements = $this->client->getPaginatedData($payload, $engagementType);\n\n foreach ($engagements['results'] as $engagement) {\n if ($engagementType == 'meetings') {\n $title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';\n } elseif ($engagementType == 'tasks') {\n $title = $engagement['properties']['hs_task_subject'];\n } else {\n $title = 'Scheduled meeting';\n }\n\n $data[] = [\n 'crmId' => $engagement['id'],\n 'subject' => $title,\n 'due' => $engagement['properties']['hs_timestamp'],\n 'type' => $engagement['properties']['hs_activity_type'] ?? null,\n ];\n }\n }\n\n usort($data, function ($item1, $item2) {\n return $item2['due'] <=> $item1['due'];\n });\n\n return $data;\n }\n\n /**\n * Try to find CRM Objects using email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $contactProperties = [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n ];\n $contact = null;\n $account = null;\n\n try {\n $hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);\n\n if ($hsContact) {\n $contact = $this->importContact($hsContact);\n $account = $contact->account;\n }\n\n $data = $this->convertCrmData($contact, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n } catch (BadRequest $e) {\n $this->logger->warning('[HubSpot] Search failed', [\n 'team_id' => $this->team->getId(),\n 'search_identifier' => $email,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return null;\n }\n\n public function getDomain(string $email): ?string\n {\n return $this->getDomainFromEmail($email);\n }\n\n /**\n * Try to find CRM objects using domain name of the email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByDomain(string $domain, ?int $userId = null): ?array\n {\n $companyName = $domain;\n\n // Try to find a company matching their email domain.\n $companyProperties = [\n 'country',\n 'phone',\n 'name',\n 'hs_avatar_filemanager_key',\n 'industry',\n 'hubspot_owner_id',\n 'domain',\n ];\n\n try {\n $hsAccounts = $this->client\n ->getInstance()\n ->companies()\n ->searchByDomain($companyName, $companyProperties);\n } catch (Throwable $e) {\n $this->logger->info('[HubSpot] Search failed', [\n 'error' => $e->getMessage(),\n 'domain' => $domain,\n ]);\n\n return null;\n }\n\n $account = null;\n // If there are multiple accounts, don't guess, we'll ask later.\n if (\\count($hsAccounts->data->results) === 1) {\n // Persist this remote object.\n $account = $this->syncAccount($hsAccounts->data->results[0]->companyId);\n }\n\n $data = $this->convertCrmData(null, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array\n {\n $countryCode = null;\n if ($contact && $contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account && $account->country_code) {\n $countryCode = $account->country_code;\n }\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n // If there are multiple opportunities, don't guess, we'll ask later.\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n protected function getCacheKey(string $object, ?int $userId = null): ?string\n {\n $key = $this->team->getId() . $object;\n $keySuffix = $this->getOwnerKeySuffix($userId);\n\n return $key . $keySuffix;\n }\n\n private function getOwnerKeySuffix(?int $userId = null): string\n {\n return $userId === null ? '' : (string) $userId;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n if (str_contains($phone, '**')) {\n return null;\n }\n\n // trim all whitespaces if present so the lookup doesn't fail\n $phone = str_replace(' ', '', $phone);\n\n // Check if the user is internal.\n if ($this->isPhoneNumberOfTeamMember($phone)) {\n return null;\n }\n\n $response = $this->searchForPhoneNumber($phone);\n if (empty($response)) {\n return null;\n }\n\n // This would ideally importContact instead but the response type differs.\n $contact = $this->findAndSyncContact($response['results'][0]['id']);\n if (! $contact instanceof Contact) {\n return null;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n\n try {\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (Exception $e) {\n $this->logger->debug('[HubSpot] Opportunity failed to sync.', [\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n private function isPhoneNumberOfTeamMember(string $phone): bool\n {\n $teamRepository = app(TeamRepository::class);\n $user = $teamRepository->findTeamMemberByPhone($this->team, $phone);\n\n if ($user instanceof User) {\n return true;\n }\n\n return false;\n }\n\n private function findAndSyncContact(string $crmId): ?Contact\n {\n try {\n return $this->syncContact($crmId);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'reason' => $exception->getMessage(),\n ]);\n\n return null;\n }\n }\n\n private function hasResults(array $response): bool\n {\n return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;\n }\n\n private function searchForPhoneNumber(string $phone): array\n {\n // Normalizes the provided phone number for the API search.\n $normalizedPhone = $this->normalizePhoneNumber($phone);\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);\n\n $this->logger->info('[HubSpot] Phone match search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);\n\n if (! $this->hasResults($response)) {\n $nationalPhone = preg_replace('/\\D/', '', phone_national(null, $phone));\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);\n\n $this->logger->info('[HubSpot] Phone match national number search triggered', [\n 'phone' => $phone,\n 'nationalPhone' => $nationalPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n if (! $this->hasResults($response)) {\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);\n\n $this->logger->info('[HubSpot] Phone match alternative search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n return $this->hasResults($response) ? $response : [];\n }\n\n private function handlePhoneSearchRequest(string $phone, array $payload): array\n {\n try {\n return $this->client->search('contacts', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'phone' => $phone,\n 'reason' => $exception->getMessage(),\n ]);\n\n return [];\n }\n }\n\n private function normalizePhoneNumber(string $phone): string\n {\n return ltrim(phone_e164(null, $phone), '+0');\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $cacheKey = $this->getCacheKey($name, $userId);\n\n $result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {\n $payload = $this->payloadBuilder->generateSearchContactsByNamePayload(\n $name,\n $this->getContactFields()\n );\n\n $hsContacts = $this->client->getPaginatedData($payload, 'contact');\n if (empty($hsContacts['results'])) {\n return false;\n }\n\n $contact = $this->importContact($hsContacts['results'][0]);\n if ($contact === null) {\n return false;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n });\n\n return is_array($result) ? $result : null;\n }\n\n\n private function convertActivityAssociations(Activity $activity): array\n {\n return [\n 'contactIds' => $this->getParticipantsIds($activity),\n 'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],\n 'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],\n 'ownerIds' => [],\n ];\n }\n\n private function getParticipantsIds(Activity $activity): array\n {\n $attendees = [];\n\n $participantRepository = app(ParticipantRepository::class);\n $participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);\n foreach ($participants as $participant) {\n if ($participant->user_id || $participant->isCoach()) {\n continue;\n }\n\n $contact = $participant->contact()->first();\n if ($contact && $contact->crm_provider_id) {\n $attendees[] = $contact->crm_provider_id;\n } else {\n if (! empty($participant->name)) {\n $attendeeData = $this->fetchMissingAttendeeInfo($participant);\n }\n if (! empty($attendeeData['id'])) {\n $attendees[] = $attendeeData['id'];\n }\n }\n }\n\n if ($activity->hasContact()) {\n $attendees[] = $activity->contact->crm_provider_id;\n }\n\n return array_unique($attendees);\n }\n\n private function fetchMissingAttendeeInfo(Participant $participant): array\n {\n // Check if we need to look inside an account context.\n $activity = $participant->getActivity();\n $companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;\n\n // First check the local data.\n /** @var Contact[] $contacts */\n $contacts = $this->team->contacts()\n ->with('account')\n ->where('name', $participant->name)\n ->whereNotNull('email')\n ->get();\n\n foreach ($contacts as $contact) {\n // If we have a company in scope, check the contact is associated to it.\n if (\n $companyId !== null\n && ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)\n ) {\n continue;\n }\n\n return [\n 'id' => $contact->crm_provider_id,\n 'email' => $contact->email,\n ];\n }\n\n $payload = $this->generateNameSearchPayload($participant->name, 0, 20);\n\n try {\n $response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);\n\n // TODO add some logic to choose the most suitable contact if multiple\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n if (empty($object['properties']) === false) {\n // Check the company matches the contact.\n // Todo: Move this check inside the API search.\n if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {\n continue;\n }\n\n return [\n 'id' => $object['id'],\n 'email' => $properties['email'],\n ];\n }\n }\n } catch (Exception $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->id_string,\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [];\n }\n\n /**\n * Store transcripts as note engagement.\n *\n * @throws Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // For HS no need to check if Crm profile - Log Notes field is enabled\n // We only check if store_transcript toggle is enabled on crm profile.\n $engagement = [\n 'active' => true,\n 'ownerId' => $this->profile->crm_provider_id,\n 'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,\n 'type' => 'NOTE',\n ];\n\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);\n\n $metadata = [\n 'body' => $transcripts,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsEngagement = $this->client\n ->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $noteId = $hsEngagement->data->engagement->id;\n\n // Store crm logged id in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $noteId;\n $transcription->save();\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $payload = [\n 'properties' => $data,\n ];\n\n try {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n $this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);\n\n break;\n case FieldData::OBJECT_CONTACT:\n $this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_ACCOUNT:\n $this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_TASK:\n // Endpoint for Engagements not ready\n $engagements = [\n 'type' => 'TASK',\n ];\n $metadata = $data;\n $this->client->getInstance()->engagements()->update($objectId, $engagements, $metadata);\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $objectId],\n $metadata,\n );\n\n break;\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException $apiException) {\n $errorMessage = $apiException->getMessage();\n if ($apiException->getResponseBody()) {\n $responseBody = json_decode($apiException->getResponseBody(), true, 512, JSON_THROW_ON_ERROR);\n $errorMessage = $responseBody['message'] ?? $apiException->getMessage();\n }\n\n $this->logger->error(\n '[HubSpot] Update record failed',\n [\n 'objectType' => $objectType,\n 'objectId' => $objectId,\n 'payload' => $payload,\n 'reason' => $errorMessage,\n 'team' => $this->team->getUuid(),\n ]\n );\n\n throw new CrmException($errorMessage);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n return $this->client->getInstance()->deals()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_CONTACT:\n return $this->client->getInstance()->contacts()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_ACCOUNT:\n return $this->client->getInstance()->companies()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_TASK:\n return $this->client->getInstance()->engagements()->get($objectId)->toArray();\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n }\n\n /**\n * @throws BadRequest\n * @throws CrmException\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n $payload = [\n 'properties' => [\n [\n 'name' => 'dealstage',\n 'value' => $stage->crm_provider_id,\n ],\n ],\n ];\n\n try {\n $this->client->getInstance()->deals()->update($crmObject->crm_provider_id, $payload);\n } catch (BadRequest $badRequest) {\n if ($badRequest->getCode() === 403) {\n throw new CrmException(\n \"Sorry, you don't have permission to update this stage.\",\n $badRequest->getCode(),\n $badRequest,\n );\n }\n\n $this->logger->warning('[HubSpot] Stage update failed', [\n 'dealId' => $crmObject->crm_provider_id,\n 'payload' => $payload,\n 'message' => $badRequest->getMessage(),\n ]);\n\n throw $badRequest;\n }\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $url = null;\n $baseUrl = 'https://app.hubspot.com/contacts/' . $this->config->crm_provider_id . '/';\n\n switch ($objectType) {\n case 'account':\n $url = $baseUrl . 'company/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n case 'task':\n case 'activity':\n return null;\n\n // This should not be deep-linked as per JMNY-3934.\n //$url = $baseUrl.'tasks/list/view/all/?taskId='.$providerId;\n break;\n }\n\n return $url;\n }\n\n public function searchCalls(Carbon $from, Carbon $to, string $activityProvider): array\n {\n $this->logger->info('[HubSpot] Search calls', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $calls = [];\n $page = 1;\n\n do {\n try {\n $payload = $this->payloadBuilder->generateGetCallsPayload($from, $to, $activityProvider, $page);\n $response = $this->client->search('calls', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n $calls = array_merge($calls, $responseResults);\n $page++;\n } while (! empty($responseResults));\n\n return $calls;\n }\n\n public function searchCallsForPeriodByPage(Carbon $from, Carbon $to, int $page, bool $retry = true)\n {\n try {\n $payload = $this->payloadBuilder->generateSearchCallsByPeriodPayload($from, $to, $page);\n\n return $this->client->search('calls', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls for period failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallsForPeriodByPage($from, $to, $page, false);\n }\n\n return null;\n }\n }\n\n public function searchCallsForPeriod(Carbon $from, Carbon $to): Generator\n {\n $this->logger->info('[HubSpot] Search calls for period', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $page = 1;\n\n do {\n $response = $this->searchCallsForPeriodByPage($from, $to, $page);\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n\n $associationContacts = $this->getAssociationDataForCollection($responseResults, 'calls', 'contacts');\n $associationCompanies = $this->getAssociationDataForCollection($responseResults, 'calls', 'companies');\n $associationDeals = $this->getAssociationDataForCollection($responseResults, 'calls', 'deals');\n\n foreach ($responseResults as $call) {\n $call['associations'] = [\n 'contacts' => $this->importAssociationData($call, $associationContacts),\n 'companies' => $this->importAssociationData($call, $associationCompanies),\n 'deals' => $this->importAssociationData($call, $associationDeals),\n ];\n\n yield $call;\n }\n $page++;\n } while (! empty($responseResults));\n }\n\n public function getCall(string $callId): array\n {\n $this->logger->info('[HubSpot] Get call', [\n 'call_id' => $callId,\n ]);\n\n $searchAttributes = $this->payloadBuilder->getSearchCallAttributes();\n $endpoint = sprintf(\n 'https://api.hubapi.com/crm/v3/objects/calls/%s',\n $callId,\n );\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'GET',\n $endpoint,\n [],\n sprintf(\n 'properties=%s&associations=contacts,companies,deals',\n implode(',', $searchAttributes),\n ),\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Get call failed', [\n 'call_id' => $callId,\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n return empty($response) ? [] : $response->toArray();\n }\n\n public function bulkAddPlaybackURLToDescription(array $crmUpdateData): array\n {\n $crmUpdateBatches = array_chunk($crmUpdateData, self::BATCH_UPDATE_LIMIT);\n\n $updatedCrmIds = [];\n\n foreach ($crmUpdateBatches as $crmBatch) {\n $payload = $this->payloadBuilder->generatePlaybackAddUrlBatchPayload($crmBatch);\n $updateSuccess = $this->bulkAddPlaybackURLToDescriptionRequest($payload);\n if ($updateSuccess) {\n $updatedCrmIds = array_merge($updatedCrmIds, array_column($crmBatch, 'crm_id'));\n }\n }\n\n return $updatedCrmIds;\n }\n\n private function bulkAddPlaybackURLToDescriptionRequest(array $payload, bool $retry = true): bool\n {\n try {\n $this->client->getNewInstance()->crm()->objects()->batchApi()->update('calls', $payload);\n\n return true;\n } catch (\\HubSpot\\Client\\Crm\\Objects\\ApiException $e) {\n $response = json_decode($e->getResponseBody(), true);\n $retryAfter =\n isset($response['policyName'])\n && $response['policyName'] == self::TEN_SECONDLY_ROLLING_POLICY\n ? self::TEN_SECONDLY_ROLLING_LIMIT\n : 1;\n } catch (Exception $e) {\n $retryAfter = 1;\n }\n\n $this->logger->warning('[HubSpot] Bulk add playback url to CRM failed', [\n 'reason' => $e->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep($retryAfter);\n\n return $this->bulkAddPlaybackURLToDescriptionRequest($payload, false);\n }\n\n return false;\n }\n\n /**\n * Sometimes we have secondly rate limit error, then retry request after 1 second\n */\n public function searchCallByRecordingURLToken(string $playbackURLToken, bool $retry = true): array\n {\n $payload = $this->payloadBuilder->generateSearchCallByTokenPayload($playbackURLToken);\n\n $this->logger->info('[HubSpot] CRM Search by playback URL token requested', [\n 'request' => $payload,\n ]);\n\n try {\n $response = $this->client->search('calls', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search by playback URL token failed', [\n 'playbackURLToken' => $playbackURLToken,\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallByRecordingURLToken($playbackURLToken, false);\n }\n\n return [];\n }\n\n return empty($response['results']) ? [] : $response['results'][0];\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! $this->config->store_transcript) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n $transcriptionSegments = $this->transcriptionService->findTranscriptionByActivity($activity);\n\n if ($transcriptionSegments->isEmpty()) {\n return '';\n }\n\n $transcription = sprintf(\n '<p><strong>Transcript for %s</strong></p><p></p>',\n $activity->title ?? $activity->activity_title,\n );\n\n $roomOwnerParticipant = $activity->findParticipantRoomOwner();\n $roomOwnerParticipantId = $roomOwnerParticipant !== null\n ? $roomOwnerParticipant->getId()\n : null;\n\n\n $transcription .= $transcriptionSegments\n ->map(static function (array $transcriptionSegment) use ($roomOwnerParticipantId): string {\n $isOrganiser = $roomOwnerParticipantId === $transcriptionSegment['participantId']\n && $roomOwnerParticipantId !== null;\n $transcriptColor = $isOrganiser ? '#000000' : '#f0415a';\n\n return sprintf(\n '<span style=\"color: %s;\">%s | </span>%s',\n $transcriptColor,\n $transcriptionSegment['formattedStartsAt'],\n $transcriptionSegment['transcript'],\n );\n })\n ->implode('<br />');\n\n return $transcription;\n }\n\n /**\n * @param array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }> $options\n *\n * @return FieldData[]\n */\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $values = [];\n $sequence = 0;\n\n foreach ($options as $option) {\n $values[] = [\n 'value' => $option['value'] ?? $option['id'],\n 'label' => substr($option['label'], 0, 255),\n 'sequence' => $sequence++,\n ];\n }\n\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n $value['value'] = substr($value['value'], 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n if (($key = array_search($value['value'], $fieldsToPurge, false)) !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n public function saveTranscriptionSummaryAsNote(\n ActivityContract $activity,\n string $title,\n string $body,\n ?string $objectId,\n ?NoteObject $noteObject = null,\n ): ?string {\n if ($noteObject === null || $objectId === null) {\n return null;\n }\n\n /** @var User $user */\n $user = $activity->getUser();\n\n $profile = $this->assignCrmOwner($user, $activity);\n if (! $profile instanceof Profile) {\n return null;\n }\n\n $timestamp = Carbon::now($user->getTimezone())->getTimestamp() * 1000;\n $engagement = [\n 'active' => true,\n 'ownerId' => $profile->getAttribute('crm_provider_id'),\n 'timestamp' => $timestamp,\n 'type' => 'NOTE',\n ];\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $body = mb_strimwidth($body, 0, self::ENGAGEMENT_BODY_MAX_LENGTH);\n $metadata = [\n 'body' => $body,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsActivityId = $this->client->createNote(\n body: $body,\n ownerId: $profile->getCrmProviderId(),\n timestamp: $timestamp,\n objectId: $objectId,\n noteObject: $noteObject,\n );\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $this->logger->info('[HubSpot] Saving Transcription Summary as Note', [\n 'activity' => $activity->getUuid(),\n 'crmActivity' => $hsActivityId,\n ]);\n\n return $hsActivityId;\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function attachSummaryToActivity(ActivityContract $activity, string $summaryTitle, string $summaryContents): bool\n {\n $this->logger->info('[HubSpot] Attaching summary to activity', [\n 'activity' => $activity->getUuid(),\n 'summary_content' => $summaryContents,\n ]);\n\n if (! $activity instanceof Activity) {\n throw new InvalidArgumentException('Expected instance of Activity');\n }\n\n $summary = '<p><strong>' . $summaryTitle . '</strong></p>';\n $summary .= '<p>' . $summaryContents . '</p>';\n $metadata = $this->buildMetadataForSummaryUpdate($activity, $summary);\n\n try {\n $type = $this->matchActivityEngagementType($activity);\n $engagement = ['type' => $type];\n\n $this->client->updateEngagement($activity->getCrmProviderId(), $engagement, $metadata);\n } catch (Exception $e) {\n $this->logger->warning('[HubSpot] Update summary failed', [\n 'activity' => $activity->getUuid(),\n 'reason' => $e->getMessage(),\n ]);\n\n return false;\n }\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $activity->getCrmProviderId()],\n $metadata,\n );\n\n return true;\n }\n\n private function buildMetadataForSummaryUpdate(Activity $activity, string $summary): array\n {\n $descriptionField = $activity->getType() === Activity::TYPE_CONFERENCE ? 'internalMeetingNotes' : 'body';\n $engagement = $this->client->getEngagementData($activity->getCrmProviderId());\n // Meeting without internalMeetingNotes might mean it just does not have any notes;\n $description = $engagement['metadata'][$descriptionField] ?? null;\n\n if (empty($description)) {\n $data = $summary;\n } else {\n // avoid playbook url link to Jiminny being sent twice in the activity description\n $targetUrl = PlaybackUrlBuilder::build($activity);\n\n if (str_contains($description, $targetUrl)) {\n $jiminnyUrl = '<p><a href=\"' . $targetUrl . '\" title=\"Play at Jiminny\">Play at Jiminny</a></p>';\n $summary = str_replace($jiminnyUrl, '', $summary);\n\n $this->logger->info('[HubSpot] Summary modified', [\n 'activity' => $activity->getUuid(),\n 'target_url' => $jiminnyUrl,\n 'modified_summary_content' => $summary,\n ]);\n }\n\n $data = $description . '<p></p>' . $summary;\n }\n\n return [\n $descriptionField => $data,\n ];\n }\n\n public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity\n {\n return $this->syncRelatedActivityManager->fetchAndAssociateRelatedActivity($activity);\n }\n\n public function fetchRelatedActivity(Activity $activity): array\n {\n return [];\n }\n\n public function getDealsInBulk(array $dealIds): array\n {\n $payload = $this->payloadBuilder->getDealsInBulkPayload($dealIds);\n\n return $this->client->getPaginatedData($payload, 'deals');\n }\n\n /**\n * Extract deal IDs from HubSpot search response.\n *\n * @param array $hubspotResponse The raw HubSpot search API response.\n * @param bool $includeArchived Whether to include archived deals (default: false).\n *\n * @return string[] Array of deal IDs as strings.\n */\n public function extractDealIds(array $hubspotResponse, bool $includeArchived = false): array\n {\n if (empty($hubspotResponse['results'])) {\n return [];\n }\n\n return array_values(\n array_map(\n fn ($deal) => $deal['id'],\n array_filter(\n $hubspotResponse['results'],\n fn ($deal) => $includeArchived || empty($deal['archived'])\n )\n )\n );\n }\n\n public function matchActivityEngagementType(Activity $activity): string\n {\n return match ($activity->getType()) {\n Activity::TYPE_CONFERENCE => self::TYPE_MEETING,\n Activity::TYPE_SOFTPHONE, Activity::TYPE_SOFTPHONE_INBOUND => self::TYPE_CALL,\n default => self::TYPE_NOTE,\n };\n }\n\n private function assignCrmOwner(User $user, ActivityContract $activity): ?Profile\n {\n $profile = $user->getProfile();\n if ($profile instanceof Profile) {\n return $profile;\n }\n\n $this->logger->info('[HubSpot] Unable to save summary. No profile', [\n 'activity' => $activity->getUuid(),\n ]);\n\n return null;\n }\n\n private static function getDealsPipelinesEndpoint(): string\n {\n return self::API_URL . self::ENDPOINT_PIPELINES . self::PIPELINE_OBJECT_TYPE_DEALS;\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n $engagement = $this->client->getEngagementData($crmProviderId);\n\n return ! empty($engagement);\n } catch (HttpNotFoundException|BadRequest) {\n // Engagement not found in CRM - this is expected and permanent\n $this->logger->info('[Hubspot] Engagement not found during verification', [\n 'engagement_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse Generator;\nuse GuzzleHttp\\Exception\\RequestException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse InvalidArgumentException;\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Contracts\\Services\\Crm\\ClientInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\FetchRelatedActivityInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\HubspotInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SavePlaybackLinkToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SendSummaryToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Contracts\\ActivityContract;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\Layout;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Participant;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\ParticipantRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Hubspot\\Actions\\SyncArchivedProfilesAction;\nuse Jiminny\\Services\\Crm\\Hubspot\\Fields\\ValueNormalizer;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\OpportunitySyncTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncCrmEntitiesTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncFieldsTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\WriteCrmTrait;\nuse Jiminny\\Services\\Crm\\MatchDomainByEmailInterface;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\ResolveCompanyNameByEmailTrait;\nuse Jiminny\\Utils\\PlaybackUrlBuilder;\nuse Sentry;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse Throwable;\nuse UnexpectedValueException;\n\n/**\n * @phpstan-type CrmFieldDefinition array{\n * name: string,\n * label: string,\n * description: string,\n * type: string,\n * fieldType: string,\n * hidden: bool,\n * showCurrencySymbol: bool,\n * options: array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }\n */\nclass Service extends BaseService implements\n HubspotInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n SendSummaryToCrmInterface,\n MatchDomainByEmailInterface,\n SavePlaybackLinkToCrmInterface,\n RemoteEntityManipulationInterface,\n FetchRelatedActivityInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use ResolveCompanyNameByEmailTrait;\n use SyncCrmEntitiesTrait;\n use WriteCrmTrait;\n use SyncFieldsTrait;\n use OpportunitySyncTrait;\n\n private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;\n\n private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';\n private const int BATCH_UPDATE_LIMIT = 100;\n private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';\n private const int TEN_SECONDLY_ROLLING_LIMIT = 10;\n\n private const string TYPE_NOTE = 'NOTE';\n\n private const string TYPE_MEETING = 'MEETING';\n\n private const string TYPE_CALL = 'CALL';\n\n private const string API_URL = 'https://api.hubapi.com';\n\n // NB: v1 is legacy - v3 is the newest\n private const string ENDPOINT_PIPELINES = '/crm-pipelines/v1/pipelines/';\n private const string PIPELINE_OBJECT_TYPE_DEALS = 'deals';\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n /**\n * @var ClientInterface|Client\n */\n protected $client;\n protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;\n protected CrmEntityRepository $crmEntityRepository;\n protected ProspectPhotoPathService $prospectPhotoPathService;\n\n private SyncFieldAction $syncFieldAction;\n private PayloadBuilder $payloadBuilder;\n private SyncRelatedActivityManager $syncRelatedActivityManager;\n private SyncArchivedProfilesAction $syncArchivedProfilesAction;\n private WebhookSyncBatchProcessor $batchProcessor;\n\n public function __construct(\n Client $client,\n SyncFieldAction $syncFieldAction,\n PayloadBuilder $payloadBuilder,\n ProspectPhotoPathService $prospectPhotoPathService,\n SyncArchivedProfilesAction $syncArchivedProfilesAction,\n WebhookSyncBatchProcessor $batchProcessor,\n ) {\n parent::__construct();\n\n $this->client = $client;\n $this->syncFieldAction = $syncFieldAction;\n $this->prospectPhotoPathService = $prospectPhotoPathService;\n $this->payloadBuilder = $payloadBuilder;\n $this->syncArchivedProfilesAction = $syncArchivedProfilesAction;\n $this->batchProcessor = $batchProcessor;\n $this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->client,\n ]);\n $this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [\n 'client' => $this->client,\n 'payloadBuilder' => $this->payloadBuilder,\n 'logger' => $this->logger,\n ]);\n $this->crmEntityRepository = app(CrmEntityRepository::class);\n $this->dealFieldsService = app(DealFieldsService::class);\n }\n\n public function getDisplayName(): string\n {\n return 'HubSpot';\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);\n }\n\n public function getClient(): Client\n {\n /** @var Client */\n return $this->client;\n }\n\n /**\n * Convert raw field data into a format compatible with CRM APIs.\n *\n * @param bool $internal Direction of the conversion.\n * True is pulling from CRM, false normalize before sending to CRM.\n */\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return ValueNormalizer::normalize(\n fieldType: $fieldType,\n fieldValue: $fieldValue,\n isInbound: $internal,\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n /** @var Field $activityField */\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'activityType',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n // Outcome should always be provided calls/meetings.\n $fieldData = [\n [\n 'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',\n 'object_type' => Field::OBJECT_TASK,\n ],\n ];\n\n foreach ($fieldData as $data) {\n $field = $this->config->fields()->where($data)->first();\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n }\n\n return $fields;\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldData = FieldDefinitions::followupFieldsFilter();\n\n foreach ($fieldData as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function syncField(Field $field): void\n {\n switch ($field->object_type) {\n case Field::OBJECT_ACCOUNT:\n $crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_CONTACT:\n $crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_OPPORTUNITY:\n $crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_TASK:\n $this->syncSingleTaskField($field);\n\n return;\n default:\n return;\n }\n\n $this->syncFieldAction->execute($field, $crmField->toArray());\n }\n\n /**\n * @param array<array{\n * id:string,\n * label:string,\n * value?:string\n * }> $options\n *\n * @throws CrmException\n *\n * @return FieldData[]\n *\n */\n public function importPicklistValues(\n Field $field,\n array $options = [['id' => '', 'label' => '', 'value' => '']],\n ): array {\n if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {\n // We already have the options, no need to fetch them again\n return $this->importOptions($field, $options);\n }\n\n $options = [];\n\n switch ($field->getObjectType()) {\n case Field::OBJECT_ACCOUNT:\n $options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_CONTACT:\n $options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_OPPORTUNITY:\n // Hubspot has different endpoint for stages\n $options = $this->getClient()->fetchOpportunityFieldOptions($field);\n\n break;\n\n case Field::OBJECT_TASK:\n if ($field->getCrmProviderId() === 'disposition') {\n $options = $this->getClient()->fetchDispositionFieldOptions();\n } elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {\n $options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);\n }\n\n break;\n\n default:\n $this->logger->warning('Invalid object type', [\n 'object_type' => $field->getObjectType(),\n 'field_id' => $field->getId(),\n ]);\n\n throw new CrmException('Invalid object type');\n }\n\n return $this->importOptions($field, $options);\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n $missingStage = null;\n\n try {\n // Use the HubSpot API client instead of the SDK crmPipelines() method\n $endpoint = self::getDealsPipelinesEndpoint();\n $pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);\n $pipelines = $pipelinesResponse->data->results;\n } catch (RequestException|BadRequest $exception) {\n throw $exception;\n }\n\n foreach ($pipelines as $pipeline) {\n $stages = [];\n\n // We create a business process to contain the pipeline, and store all stages against it.\n $p = ResponseNormalize::normalizePipeline($pipeline);\n\n // Create/update business process for this pipeline\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => $p['active'],\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n // Create/update record type clone\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'is_selectable' => $p['active'],\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n // Stages - fetch all existing stages upfront to avoid N+1 queries\n $existingStages = $this->config->stages()\n ->withTrashed()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get()\n ->keyBy('crm_provider_id');\n\n foreach ($p['stages'] as $dealStage) {\n $s = ResponseNormalize::normalizeDealStage($dealStage);\n\n /** @var ?Stage $existingStage */\n $existingStage = $existingStages->get($s['id']);\n\n // Restore soft-deleted stages that are now active in HubSpot\n if ($existingStage?->trashed() && $s['active']) {\n $existingStage->restore();\n }\n\n // Upsert stage (updates soft-deleted records without restoring them)\n $stage = $this->config->stages()->withTrashed()->updateOrCreate([\n 'crm_provider_id' => $s['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($s['label'], 0, 50),\n 'label' => mb_strimwidth($s['label'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $s['displayOrder'],\n 'is_selectable' => $s['active'],\n 'probability' => $s['probability'] * 100,\n ]);\n\n if ($missingStageName === $s['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage->id;\n }\n\n $businessProcess->stages()->sync($stages);\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n try {\n $endpoint = 'https://api.hubapi.com/integrations/v1/me';\n $response = $this->client->getInstance()->getClient()->request('get', $endpoint);\n\n $accountData = $response->data;\n $this->config->update(['default_currency' => $accountData->currency]);\n } catch (BadRequest $e) {\n throw new CrmException('Could not sync the organization.', $e->getCode(), $e);\n }\n }\n\n /**\n * @inheritdoc\n *\n * @throws CrmException\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $this->syncArchivedProfilesAction->execute($this->team, $this->client, $this->config);\n\n try {\n $owners = $this->client->getOwners();\n } catch (\\HubSpot\\Client\\Crm\\Owners\\ApiException $e) {\n $this->logger->error('[HubSpot] Could not sync the profiles.', [\n 'team_id' => $this->team->getId(),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new CrmException('Could not sync the profiles.', $e->getCode(), $e);\n }\n\n $profileRepository = app(ProfileRepository::class);\n $teamRepository = app(TeamRepository::class);\n\n foreach ($owners as $owner) {\n if ($owner->getArchived()) {\n // not supposed to fetch archived, but log anyway\n $this->logger->warning('[HubSpot] Found archived owner', [\n 'crm_provider_id' => $owner->getId(),\n 'email' => $owner->getEmail(),\n ]);\n\n continue;\n }\n\n $email = $owner->getEmail();\n if ($email === null) {\n continue;\n }\n\n $user = $teamRepository->findActiveTeamMemberByEmail($this->team, $email);\n\n if (! $user instanceof User) {\n continue;\n }\n\n $profile = $profileRepository->updateOrCreateProfile($user, [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $owner->getId(),\n ]);\n\n if ($userToSearch && $userToSearch->getId() === $user->getId()) {\n return $profile;\n }\n }\n\n return null;\n }\n\n private function generateNameSearchPayload(string $name, int $offset, int $limit): array\n {\n $payload = [\n 'query' => $name,\n 'sorts' => [\n [\n 'propertyName' => 'modifieddate',\n 'direction' => 'DESCENDING',\n ],\n ],\n 'properties' => [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n 'industry',\n 'name',\n 'company',\n ],\n 'limit' => $limit,\n 'after' => $offset,\n ];\n\n $this->logger->debug('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n return $payload;\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n /** @var array<int, array<string, mixed>> */\n return Cache::remember(\n key: $this->team->getId() . $name . $count . $offset,\n ttl: 300,\n callback: function () use ($name, $offset, $count): array {\n $data = [];\n\n // Use the new V3 API to find contacts based on additional fields.\n foreach (['companies', 'contacts'] as $objectType) {\n $payload = $this->generateNameSearchPayload($name, $offset, $count);\n $type = $objectType === 'companies' ? 'account' : 'contact';\n\n try {\n $response = $this->client->search($objectType, $payload);\n\n // Build mapped list.\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n\n $objectName = $this->buildContactName($properties);\n\n $record = [\n 'crmId' => $object['id'],\n // Pass crmUrl to the FE, needed for success message in the extension when you log activity.\n 'crmUrl' => $this->generateProviderUrl($object['id'], $type),\n 'name' => $objectName,\n 'prospectType' => $type,\n 'phoneNumbers' => [],\n ];\n\n if ($type === 'account') {\n $record['industry'] = $properties['industry'] ?? null;\n } else {\n $record['title'] = $properties['jobtitle'] ?? null;\n $record['organization'] = $properties['company'] ?? null;\n }\n\n $countryCode = $this->buildContactCountry($properties);\n $parsedNumber = $this->buildContactPhone($countryCode, $properties);\n\n // Add phone number to record.\n if (! empty($parsedNumber['phone'])) {\n $record['phoneNumbers'][] = [\n 'number' => $parsedNumber['phone'],\n 'nationalFormat' => phone_national($countryCode, $parsedNumber['phone']),\n 'type' => 'phone',\n ];\n }\n\n // Add mobile phone number to record.\n if (! empty($properties['mobilephone'])) {\n $mobileNumber = phone_e164($countryCode, $properties['mobilephone']);\n if ($mobileNumber !== null) {\n $record['phoneNumbers'][] = [\n 'number' => $mobileNumber,\n 'nationalFormat' => phone_national($countryCode, $mobileNumber),\n 'type' => 'mobile',\n ];\n }\n }\n\n $data[] = $record;\n }\n } catch (BadRequest $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->getUuid(),\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n }\n\n return $data;\n },\n );\n }\n\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n\n if ($crmAccountId === null) {\n return $data;\n }\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n $closedStages = $this->getClosedDealStages();\n $payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(\n $this->config,\n $crmAccountId,\n $closedStages,\n );\n\n $results = $this->client->getPaginatedData($payload, 'deals');\n\n foreach ($results['results'] as $object) {\n $properties = $object['properties'];\n\n $amount = null;\n if (empty($properties['amount']) === false) {\n $currency = $properties['deal_currency_code'] ?? $this->config->default_currency;\n\n // Values can contain commas and any junk so strip them.\n $value = (float) preg_replace('/[^\\d.]/', '', $properties['amount']);\n $amount = formatCurrency($value, $currency);\n }\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n } else {\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', $properties['dealstage'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages(null, $properties['dealstage']);\n }\n }\n\n $recordType = null;\n if ($businessProcess) {\n $recordType = $businessProcess->recordTypes()->first();\n }\n\n $isWon = in_array($properties['dealstage'], $closedStages['won']);\n $isLost = in_array($properties['dealstage'], $closedStages['lost']);\n\n $record = [\n 'crmId' => $object['id'],\n 'name' => $properties['dealname'] ?? 'Unknown Deal',\n 'value' => $amount,\n 'won' => $isWon,\n 'closed' => $isWon || $isLost,\n 'stage' => [\n 'id' => $stage?->getUuid() ?? '',\n 'name' => $stage?->getName() ?? '',\n ],\n ];\n\n if ($recordType) {\n $record += [\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n }\n\n if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = [];\n switch ($objectType) {\n case 'contact':\n $hsObject = 'contact';\n\n break;\n case 'account':\n $hsObject = 'company';\n\n break;\n default:\n // This is a hack to prioritise and override a contact/company with a deal.\n if ($opportunityId) {\n $hsObject = 'deal';\n $objectId = $opportunityId;\n } else {\n throw new InvalidArgumentException('Object type not supported.');\n }\n }\n\n $engagementTypes = ['meetings', 'tasks'];\n\n foreach ($engagementTypes as $engagementType) {\n $payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);\n\n $this->logger->info('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n $engagements = $this->client->getPaginatedData($payload, $engagementType);\n\n foreach ($engagements['results'] as $engagement) {\n if ($engagementType == 'meetings') {\n $title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';\n } elseif ($engagementType == 'tasks') {\n $title = $engagement['properties']['hs_task_subject'];\n } else {\n $title = 'Scheduled meeting';\n }\n\n $data[] = [\n 'crmId' => $engagement['id'],\n 'subject' => $title,\n 'due' => $engagement['properties']['hs_timestamp'],\n 'type' => $engagement['properties']['hs_activity_type'] ?? null,\n ];\n }\n }\n\n usort($data, function ($item1, $item2) {\n return $item2['due'] <=> $item1['due'];\n });\n\n return $data;\n }\n\n /**\n * Try to find CRM Objects using email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $contactProperties = [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n ];\n $contact = null;\n $account = null;\n\n try {\n $hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);\n\n if ($hsContact) {\n $contact = $this->importContact($hsContact);\n $account = $contact->account;\n }\n\n $data = $this->convertCrmData($contact, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n } catch (BadRequest $e) {\n $this->logger->warning('[HubSpot] Search failed', [\n 'team_id' => $this->team->getId(),\n 'search_identifier' => $email,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return null;\n }\n\n public function getDomain(string $email): ?string\n {\n return $this->getDomainFromEmail($email);\n }\n\n /**\n * Try to find CRM objects using domain name of the email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByDomain(string $domain, ?int $userId = null): ?array\n {\n $companyName = $domain;\n\n // Try to find a company matching their email domain.\n $companyProperties = [\n 'country',\n 'phone',\n 'name',\n 'hs_avatar_filemanager_key',\n 'industry',\n 'hubspot_owner_id',\n 'domain',\n ];\n\n try {\n $hsAccounts = $this->client\n ->getInstance()\n ->companies()\n ->searchByDomain($companyName, $companyProperties);\n } catch (Throwable $e) {\n $this->logger->info('[HubSpot] Search failed', [\n 'error' => $e->getMessage(),\n 'domain' => $domain,\n ]);\n\n return null;\n }\n\n $account = null;\n // If there are multiple accounts, don't guess, we'll ask later.\n if (\\count($hsAccounts->data->results) === 1) {\n // Persist this remote object.\n $account = $this->syncAccount($hsAccounts->data->results[0]->companyId);\n }\n\n $data = $this->convertCrmData(null, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array\n {\n $countryCode = null;\n if ($contact && $contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account && $account->country_code) {\n $countryCode = $account->country_code;\n }\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n // If there are multiple opportunities, don't guess, we'll ask later.\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n protected function getCacheKey(string $object, ?int $userId = null): ?string\n {\n $key = $this->team->getId() . $object;\n $keySuffix = $this->getOwnerKeySuffix($userId);\n\n return $key . $keySuffix;\n }\n\n private function getOwnerKeySuffix(?int $userId = null): string\n {\n return $userId === null ? '' : (string) $userId;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n if (str_contains($phone, '**')) {\n return null;\n }\n\n // trim all whitespaces if present so the lookup doesn't fail\n $phone = str_replace(' ', '', $phone);\n\n // Check if the user is internal.\n if ($this->isPhoneNumberOfTeamMember($phone)) {\n return null;\n }\n\n $response = $this->searchForPhoneNumber($phone);\n if (empty($response)) {\n return null;\n }\n\n // This would ideally importContact instead but the response type differs.\n $contact = $this->findAndSyncContact($response['results'][0]['id']);\n if (! $contact instanceof Contact) {\n return null;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n\n try {\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (Exception $e) {\n $this->logger->debug('[HubSpot] Opportunity failed to sync.', [\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n private function isPhoneNumberOfTeamMember(string $phone): bool\n {\n $teamRepository = app(TeamRepository::class);\n $user = $teamRepository->findTeamMemberByPhone($this->team, $phone);\n\n if ($user instanceof User) {\n return true;\n }\n\n return false;\n }\n\n private function findAndSyncContact(string $crmId): ?Contact\n {\n try {\n return $this->syncContact($crmId);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'reason' => $exception->getMessage(),\n ]);\n\n return null;\n }\n }\n\n private function hasResults(array $response): bool\n {\n return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;\n }\n\n private function searchForPhoneNumber(string $phone): array\n {\n // Normalizes the provided phone number for the API search.\n $normalizedPhone = $this->normalizePhoneNumber($phone);\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);\n\n $this->logger->info('[HubSpot] Phone match search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);\n\n if (! $this->hasResults($response)) {\n $nationalPhone = preg_replace('/\\D/', '', phone_national(null, $phone));\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);\n\n $this->logger->info('[HubSpot] Phone match national number search triggered', [\n 'phone' => $phone,\n 'nationalPhone' => $nationalPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n if (! $this->hasResults($response)) {\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);\n\n $this->logger->info('[HubSpot] Phone match alternative search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n return $this->hasResults($response) ? $response : [];\n }\n\n private function handlePhoneSearchRequest(string $phone, array $payload): array\n {\n try {\n return $this->client->search('contacts', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'phone' => $phone,\n 'reason' => $exception->getMessage(),\n ]);\n\n return [];\n }\n }\n\n private function normalizePhoneNumber(string $phone): string\n {\n return ltrim(phone_e164(null, $phone), '+0');\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $cacheKey = $this->getCacheKey($name, $userId);\n\n $result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {\n $payload = $this->payloadBuilder->generateSearchContactsByNamePayload(\n $name,\n $this->getContactFields()\n );\n\n $hsContacts = $this->client->getPaginatedData($payload, 'contact');\n if (empty($hsContacts['results'])) {\n return false;\n }\n\n $contact = $this->importContact($hsContacts['results'][0]);\n if ($contact === null) {\n return false;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n });\n\n return is_array($result) ? $result : null;\n }\n\n\n private function convertActivityAssociations(Activity $activity): array\n {\n return [\n 'contactIds' => $this->getParticipantsIds($activity),\n 'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],\n 'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],\n 'ownerIds' => [],\n ];\n }\n\n private function getParticipantsIds(Activity $activity): array\n {\n $attendees = [];\n\n $participantRepository = app(ParticipantRepository::class);\n $participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);\n foreach ($participants as $participant) {\n if ($participant->user_id || $participant->isCoach()) {\n continue;\n }\n\n $contact = $participant->contact()->first();\n if ($contact && $contact->crm_provider_id) {\n $attendees[] = $contact->crm_provider_id;\n } else {\n if (! empty($participant->name)) {\n $attendeeData = $this->fetchMissingAttendeeInfo($participant);\n }\n if (! empty($attendeeData['id'])) {\n $attendees[] = $attendeeData['id'];\n }\n }\n }\n\n if ($activity->hasContact()) {\n $attendees[] = $activity->contact->crm_provider_id;\n }\n\n return array_unique($attendees);\n }\n\n private function fetchMissingAttendeeInfo(Participant $participant): array\n {\n // Check if we need to look inside an account context.\n $activity = $participant->getActivity();\n $companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;\n\n // First check the local data.\n /** @var Contact[] $contacts */\n $contacts = $this->team->contacts()\n ->with('account')\n ->where('name', $participant->name)\n ->whereNotNull('email')\n ->get();\n\n foreach ($contacts as $contact) {\n // If we have a company in scope, check the contact is associated to it.\n if (\n $companyId !== null\n && ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)\n ) {\n continue;\n }\n\n return [\n 'id' => $contact->crm_provider_id,\n 'email' => $contact->email,\n ];\n }\n\n $payload = $this->generateNameSearchPayload($participant->name, 0, 20);\n\n try {\n $response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);\n\n // TODO add some logic to choose the most suitable contact if multiple\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n if (empty($object['properties']) === false) {\n // Check the company matches the contact.\n // Todo: Move this check inside the API search.\n if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {\n continue;\n }\n\n return [\n 'id' => $object['id'],\n 'email' => $properties['email'],\n ];\n }\n }\n } catch (Exception $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->id_string,\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [];\n }\n\n /**\n * Store transcripts as note engagement.\n *\n * @throws Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // For HS no need to check if Crm profile - Log Notes field is enabled\n // We only check if store_transcript toggle is enabled on crm profile.\n $engagement = [\n 'active' => true,\n 'ownerId' => $this->profile->crm_provider_id,\n 'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,\n 'type' => 'NOTE',\n ];\n\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);\n\n $metadata = [\n 'body' => $transcripts,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsEngagement = $this->client\n ->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $noteId = $hsEngagement->data->engagement->id;\n\n // Store crm logged id in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $noteId;\n $transcription->save();\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $payload = [\n 'properties' => $data,\n ];\n\n try {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n $this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);\n\n break;\n case FieldData::OBJECT_CONTACT:\n $this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_ACCOUNT:\n $this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_TASK:\n // Endpoint for Engagements not ready\n $engagements = [\n 'type' => 'TASK',\n ];\n $metadata = $data;\n $this->client->getInstance()->engagements()->update($objectId, $engagements, $metadata);\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $objectId],\n $metadata,\n );\n\n break;\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException $apiException) {\n $errorMessage = $apiException->getMessage();\n if ($apiException->getResponseBody()) {\n $responseBody = json_decode($apiException->getResponseBody(), true, 512, JSON_THROW_ON_ERROR);\n $errorMessage = $responseBody['message'] ?? $apiException->getMessage();\n }\n\n $this->logger->error(\n '[HubSpot] Update record failed',\n [\n 'objectType' => $objectType,\n 'objectId' => $objectId,\n 'payload' => $payload,\n 'reason' => $errorMessage,\n 'team' => $this->team->getUuid(),\n ]\n );\n\n throw new CrmException($errorMessage);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n return $this->client->getInstance()->deals()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_CONTACT:\n return $this->client->getInstance()->contacts()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_ACCOUNT:\n return $this->client->getInstance()->companies()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_TASK:\n return $this->client->getInstance()->engagements()->get($objectId)->toArray();\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n }\n\n /**\n * @throws BadRequest\n * @throws CrmException\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n $payload = [\n 'properties' => [\n [\n 'name' => 'dealstage',\n 'value' => $stage->crm_provider_id,\n ],\n ],\n ];\n\n try {\n $this->client->getInstance()->deals()->update($crmObject->crm_provider_id, $payload);\n } catch (BadRequest $badRequest) {\n if ($badRequest->getCode() === 403) {\n throw new CrmException(\n \"Sorry, you don't have permission to update this stage.\",\n $badRequest->getCode(),\n $badRequest,\n );\n }\n\n $this->logger->warning('[HubSpot] Stage update failed', [\n 'dealId' => $crmObject->crm_provider_id,\n 'payload' => $payload,\n 'message' => $badRequest->getMessage(),\n ]);\n\n throw $badRequest;\n }\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $url = null;\n $baseUrl = 'https://app.hubspot.com/contacts/' . $this->config->crm_provider_id . '/';\n\n switch ($objectType) {\n case 'account':\n $url = $baseUrl . 'company/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n case 'task':\n case 'activity':\n return null;\n\n // This should not be deep-linked as per JMNY-3934.\n //$url = $baseUrl.'tasks/list/view/all/?taskId='.$providerId;\n break;\n }\n\n return $url;\n }\n\n public function searchCalls(Carbon $from, Carbon $to, string $activityProvider): array\n {\n $this->logger->info('[HubSpot] Search calls', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $calls = [];\n $page = 1;\n\n do {\n try {\n $payload = $this->payloadBuilder->generateGetCallsPayload($from, $to, $activityProvider, $page);\n $response = $this->client->search('calls', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n $calls = array_merge($calls, $responseResults);\n $page++;\n } while (! empty($responseResults));\n\n return $calls;\n }\n\n public function searchCallsForPeriodByPage(Carbon $from, Carbon $to, int $page, bool $retry = true)\n {\n try {\n $payload = $this->payloadBuilder->generateSearchCallsByPeriodPayload($from, $to, $page);\n\n return $this->client->search('calls', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls for period failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallsForPeriodByPage($from, $to, $page, false);\n }\n\n return null;\n }\n }\n\n public function searchCallsForPeriod(Carbon $from, Carbon $to): Generator\n {\n $this->logger->info('[HubSpot] Search calls for period', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $page = 1;\n\n do {\n $response = $this->searchCallsForPeriodByPage($from, $to, $page);\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n\n $associationContacts = $this->getAssociationDataForCollection($responseResults, 'calls', 'contacts');\n $associationCompanies = $this->getAssociationDataForCollection($responseResults, 'calls', 'companies');\n $associationDeals = $this->getAssociationDataForCollection($responseResults, 'calls', 'deals');\n\n foreach ($responseResults as $call) {\n $call['associations'] = [\n 'contacts' => $this->importAssociationData($call, $associationContacts),\n 'companies' => $this->importAssociationData($call, $associationCompanies),\n 'deals' => $this->importAssociationData($call, $associationDeals),\n ];\n\n yield $call;\n }\n $page++;\n } while (! empty($responseResults));\n }\n\n public function getCall(string $callId): array\n {\n $this->logger->info('[HubSpot] Get call', [\n 'call_id' => $callId,\n ]);\n\n $searchAttributes = $this->payloadBuilder->getSearchCallAttributes();\n $endpoint = sprintf(\n 'https://api.hubapi.com/crm/v3/objects/calls/%s',\n $callId,\n );\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'GET',\n $endpoint,\n [],\n sprintf(\n 'properties=%s&associations=contacts,companies,deals',\n implode(',', $searchAttributes),\n ),\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Get call failed', [\n 'call_id' => $callId,\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n return empty($response) ? [] : $response->toArray();\n }\n\n public function bulkAddPlaybackURLToDescription(array $crmUpdateData): array\n {\n $crmUpdateBatches = array_chunk($crmUpdateData, self::BATCH_UPDATE_LIMIT);\n\n $updatedCrmIds = [];\n\n foreach ($crmUpdateBatches as $crmBatch) {\n $payload = $this->payloadBuilder->generatePlaybackAddUrlBatchPayload($crmBatch);\n $updateSuccess = $this->bulkAddPlaybackURLToDescriptionRequest($payload);\n if ($updateSuccess) {\n $updatedCrmIds = array_merge($updatedCrmIds, array_column($crmBatch, 'crm_id'));\n }\n }\n\n return $updatedCrmIds;\n }\n\n private function bulkAddPlaybackURLToDescriptionRequest(array $payload, bool $retry = true): bool\n {\n try {\n $this->client->getNewInstance()->crm()->objects()->batchApi()->update('calls', $payload);\n\n return true;\n } catch (\\HubSpot\\Client\\Crm\\Objects\\ApiException $e) {\n $response = json_decode($e->getResponseBody(), true);\n $retryAfter =\n isset($response['policyName'])\n && $response['policyName'] == self::TEN_SECONDLY_ROLLING_POLICY\n ? self::TEN_SECONDLY_ROLLING_LIMIT\n : 1;\n } catch (Exception $e) {\n $retryAfter = 1;\n }\n\n $this->logger->warning('[HubSpot] Bulk add playback url to CRM failed', [\n 'reason' => $e->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep($retryAfter);\n\n return $this->bulkAddPlaybackURLToDescriptionRequest($payload, false);\n }\n\n return false;\n }\n\n /**\n * Sometimes we have secondly rate limit error, then retry request after 1 second\n */\n public function searchCallByRecordingURLToken(string $playbackURLToken, bool $retry = true): array\n {\n $payload = $this->payloadBuilder->generateSearchCallByTokenPayload($playbackURLToken);\n\n $this->logger->info('[HubSpot] CRM Search by playback URL token requested', [\n 'request' => $payload,\n ]);\n\n try {\n $response = $this->client->search('calls', $payload);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search by playback URL token failed', [\n 'playbackURLToken' => $playbackURLToken,\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallByRecordingURLToken($playbackURLToken, false);\n }\n\n return [];\n }\n\n return empty($response['results']) ? [] : $response['results'][0];\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! $this->config->store_transcript) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n $transcriptionSegments = $this->transcriptionService->findTranscriptionByActivity($activity);\n\n if ($transcriptionSegments->isEmpty()) {\n return '';\n }\n\n $transcription = sprintf(\n '<p><strong>Transcript for %s</strong></p><p></p>',\n $activity->title ?? $activity->activity_title,\n );\n\n $roomOwnerParticipant = $activity->findParticipantRoomOwner();\n $roomOwnerParticipantId = $roomOwnerParticipant !== null\n ? $roomOwnerParticipant->getId()\n : null;\n\n\n $transcription .= $transcriptionSegments\n ->map(static function (array $transcriptionSegment) use ($roomOwnerParticipantId): string {\n $isOrganiser = $roomOwnerParticipantId === $transcriptionSegment['participantId']\n && $roomOwnerParticipantId !== null;\n $transcriptColor = $isOrganiser ? '#000000' : '#f0415a';\n\n return sprintf(\n '<span style=\"color: %s;\">%s | </span>%s',\n $transcriptColor,\n $transcriptionSegment['formattedStartsAt'],\n $transcriptionSegment['transcript'],\n );\n })\n ->implode('<br />');\n\n return $transcription;\n }\n\n /**\n * @param array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }> $options\n *\n * @return FieldData[]\n */\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $values = [];\n $sequence = 0;\n\n foreach ($options as $option) {\n $values[] = [\n 'value' => $option['value'] ?? $option['id'],\n 'label' => substr($option['label'], 0, 255),\n 'sequence' => $sequence++,\n ];\n }\n\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n $value['value'] = substr($value['value'], 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n if (($key = array_search($value['value'], $fieldsToPurge, false)) !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n public function saveTranscriptionSummaryAsNote(\n ActivityContract $activity,\n string $title,\n string $body,\n ?string $objectId,\n ?NoteObject $noteObject = null,\n ): ?string {\n if ($noteObject === null || $objectId === null) {\n return null;\n }\n\n /** @var User $user */\n $user = $activity->getUser();\n\n $profile = $this->assignCrmOwner($user, $activity);\n if (! $profile instanceof Profile) {\n return null;\n }\n\n $timestamp = Carbon::now($user->getTimezone())->getTimestamp() * 1000;\n $engagement = [\n 'active' => true,\n 'ownerId' => $profile->getAttribute('crm_provider_id'),\n 'timestamp' => $timestamp,\n 'type' => 'NOTE',\n ];\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $body = mb_strimwidth($body, 0, self::ENGAGEMENT_BODY_MAX_LENGTH);\n $metadata = [\n 'body' => $body,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsActivityId = $this->client->createNote(\n body: $body,\n ownerId: $profile->getCrmProviderId(),\n timestamp: $timestamp,\n objectId: $objectId,\n noteObject: $noteObject,\n );\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $this->logger->info('[HubSpot] Saving Transcription Summary as Note', [\n 'activity' => $activity->getUuid(),\n 'crmActivity' => $hsActivityId,\n ]);\n\n return $hsActivityId;\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function attachSummaryToActivity(ActivityContract $activity, string $summaryTitle, string $summaryContents): bool\n {\n $this->logger->info('[HubSpot] Attaching summary to activity', [\n 'activity' => $activity->getUuid(),\n 'summary_content' => $summaryContents,\n ]);\n\n if (! $activity instanceof Activity) {\n throw new InvalidArgumentException('Expected instance of Activity');\n }\n\n $summary = '<p><strong>' . $summaryTitle . '</strong></p>';\n $summary .= '<p>' . $summaryContents . '</p>';\n $metadata = $this->buildMetadataForSummaryUpdate($activity, $summary);\n\n try {\n $type = $this->matchActivityEngagementType($activity);\n $engagement = ['type' => $type];\n\n $this->client->updateEngagement($activity->getCrmProviderId(), $engagement, $metadata);\n } catch (Exception $e) {\n $this->logger->warning('[HubSpot] Update summary failed', [\n 'activity' => $activity->getUuid(),\n 'reason' => $e->getMessage(),\n ]);\n\n return false;\n }\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $activity->getCrmProviderId()],\n $metadata,\n );\n\n return true;\n }\n\n private function buildMetadataForSummaryUpdate(Activity $activity, string $summary): array\n {\n $descriptionField = $activity->getType() === Activity::TYPE_CONFERENCE ? 'internalMeetingNotes' : 'body';\n $engagement = $this->client->getEngagementData($activity->getCrmProviderId());\n // Meeting without internalMeetingNotes might mean it just does not have any notes;\n $description = $engagement['metadata'][$descriptionField] ?? null;\n\n if (empty($description)) {\n $data = $summary;\n } else {\n // avoid playbook url link to Jiminny being sent twice in the activity description\n $targetUrl = PlaybackUrlBuilder::build($activity);\n\n if (str_contains($description, $targetUrl)) {\n $jiminnyUrl = '<p><a href=\"' . $targetUrl . '\" title=\"Play at Jiminny\">Play at Jiminny</a></p>';\n $summary = str_replace($jiminnyUrl, '', $summary);\n\n $this->logger->info('[HubSpot] Summary modified', [\n 'activity' => $activity->getUuid(),\n 'target_url' => $jiminnyUrl,\n 'modified_summary_content' => $summary,\n ]);\n }\n\n $data = $description . '<p></p>' . $summary;\n }\n\n return [\n $descriptionField => $data,\n ];\n }\n\n public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity\n {\n return $this->syncRelatedActivityManager->fetchAndAssociateRelatedActivity($activity);\n }\n\n public function fetchRelatedActivity(Activity $activity): array\n {\n return [];\n }\n\n public function getDealsInBulk(array $dealIds): array\n {\n $payload = $this->payloadBuilder->getDealsInBulkPayload($dealIds);\n\n return $this->client->getPaginatedData($payload, 'deals');\n }\n\n /**\n * Extract deal IDs from HubSpot search response.\n *\n * @param array $hubspotResponse The raw HubSpot search API response.\n * @param bool $includeArchived Whether to include archived deals (default: false).\n *\n * @return string[] Array of deal IDs as strings.\n */\n public function extractDealIds(array $hubspotResponse, bool $includeArchived = false): array\n {\n if (empty($hubspotResponse['results'])) {\n return [];\n }\n\n return array_values(\n array_map(\n fn ($deal) => $deal['id'],\n array_filter(\n $hubspotResponse['results'],\n fn ($deal) => $includeArchived || empty($deal['archived'])\n )\n )\n );\n }\n\n public function matchActivityEngagementType(Activity $activity): string\n {\n return match ($activity->getType()) {\n Activity::TYPE_CONFERENCE => self::TYPE_MEETING,\n Activity::TYPE_SOFTPHONE, Activity::TYPE_SOFTPHONE_INBOUND => self::TYPE_CALL,\n default => self::TYPE_NOTE,\n };\n }\n\n private function assignCrmOwner(User $user, ActivityContract $activity): ?Profile\n {\n $profile = $user->getProfile();\n if ($profile instanceof Profile) {\n return $profile;\n }\n\n $this->logger->info('[HubSpot] Unable to save summary. No profile', [\n 'activity' => $activity->getUuid(),\n ]);\n\n return null;\n }\n\n private static function getDealsPipelinesEndpoint(): string\n {\n return self::API_URL . self::ENDPOINT_PIPELINES . self::PIPELINE_OBJECT_TYPE_DEALS;\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n $engagement = $this->client->getEngagementData($crmProviderId);\n\n return ! empty($engagement);\n } catch (HttpNotFoundException|BadRequest) {\n // Engagement not found in CRM - this is expected and permanent\n $this->logger->info('[Hubspot] Engagement not found during verification', [\n 'engagement_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3419229447380999607
|
-465194999110035353
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Show Replace Field
Search History
doSearch
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/1
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Code changed:
Hide
Sync Changes
Hide This Notification
7
48
1
33
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Hubspot;
use Carbon\Carbon;
use Exception;
use Generator;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Cache;
use InvalidArgumentException;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\FetchRelatedActivityInterface;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SavePlaybackLinkToCrmInterface;
use Jiminny\Contracts\Services\Crm\SendSummaryToCrmInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Contracts\ActivityContract;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Participant;
use Jiminny\Models\Playbook;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\ParticipantRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Hubspot\Actions\SyncArchivedProfilesAction;
use Jiminny\Services\Crm\Hubspot\Fields\ValueNormalizer;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\OpportunitySyncTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncCrmEntitiesTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncFieldsTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\WriteCrmTrait;
use Jiminny\Services\Crm\MatchDomainByEmailInterface;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\ResolveCompanyNameByEmailTrait;
use Jiminny\Utils\PlaybackUrlBuilder;
use Sentry;
use SevenShores\Hubspot\Exceptions\BadRequest;
use Throwable;
use UnexpectedValueException;
/**
* @phpstan-type CrmFieldDefinition array{
* name: string,
* label: string,
* description: string,
* type: string,
* fieldType: string,
* hidden: bool,
* showCurrencySymbol: bool,
* options: array<array{
* id: string,
* label: string,
* value?: string,
* }
*/
class Service extends BaseService implements
HubspotInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
SendSummaryToCrmInterface,
MatchDomainByEmailInterface,
SavePlaybackLinkToCrmInterface,
RemoteEntityManipulationInterface,
FetchRelatedActivityInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use ResolveCompanyNameByEmailTrait;
use SyncCrmEntitiesTrait;
use WriteCrmTrait;
use SyncFieldsTrait;
use OpportunitySyncTrait;
private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;
private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';
private const int BATCH_UPDATE_LIMIT = 100;
private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';
private const int TEN_SECONDLY_ROLLING_LIMIT = 10;
private const string TYPE_NOTE = 'NOTE';
private const string TYPE_MEETING = 'MEETING';
private const string TYPE_CALL = 'CALL';
private const string API_URL = '[URL_WITH_CREDENTIALS] ClientInterface|Client
*/
protected $client;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected ProspectPhotoPathService $prospectPhotoPathService;
private SyncFieldAction $syncFieldAction;
private PayloadBuilder $payloadBuilder;
private SyncRelatedActivityManager $syncRelatedActivityManager;
private SyncArchivedProfilesAction $syncArchivedProfilesAction;
private WebhookSyncBatchProcessor $batchProcessor;
public function __construct(
Client $client,
SyncFieldAction $syncFieldAction,
PayloadBuilder $payloadBuilder,
ProspectPhotoPathService $prospectPhotoPathService,
SyncArchivedProfilesAction $syncArchivedProfilesAction,
WebhookSyncBatchProcessor $batchProcessor,
) {
parent::__construct();
$this->client = $client;
$this->syncFieldAction = $syncFieldAction;
$this->prospectPhotoPathService = $prospectPhotoPathService;
$this->payloadBuilder = $payloadBuilder;
$this->syncArchivedProfilesAction = $syncArchivedProfilesAction;
$this->batchProcessor = $batchProcessor;
$this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [
'client' => $this->client,
'payloadBuilder' => $this->payloadBuilder,
'logger' => $this->logger,
]);
$this->crmEntityRepository = app(CrmEntityRepository::class);
$this->dealFieldsService = app(DealFieldsService::class);
}
public function getDisplayName(): string
{
return 'HubSpot';
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);
}
public function getClient(): Client
{
/** @var Client */
return $this->client;
}
/**
* Convert raw field data into a format compatible with CRM APIs.
*
* @param bool $internal Direction of the conversion.
* True is pulling from CRM, false normalize before sending to CRM.
*/
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return ValueNormalizer::normalize(
fieldType: $fieldType,
fieldValue: $fieldValue,
isInbound: $internal,
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'activityType',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
/**
* @inheritdoc
*/
public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
// Outcome should always be provided calls/meetings.
$fieldData = [
[
'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',
'object_type' => Field::OBJECT_TASK,
],
];
foreach ($fieldData as $data) {
$field = $this->config->fields()->where($data)->first();
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
}
return $fields;
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function syncField(Field $field): void
{
switch ($field->object_type) {
case Field::OBJECT_ACCOUNT:
$crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_CONTACT:
$crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_OPPORTUNITY:
$crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_TASK:
$this->syncSingleTaskField($field);
return;
default:
return;
}
$this->syncFieldAction->execute($field, $crmField->toArray());
}
/**
* @param array<array{
* id:string,
* label:string,
* value?:string
* }> $options
*
* @throws CrmException
*
* @return FieldData[]
*
*/
public function importPicklistValues(
Field $field,
array $options = [['id' => '', 'label' => '', 'value' => '']],
): array {
if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {
// We already have the options, no need to fetch them again
return $this->importOptions($field, $options);
}
$options = [];
switch ($field->getObjectType()) {
case Field::OBJECT_ACCOUNT:
$options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());
break;
case Field::OBJECT_CONTACT:
$options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());
break;
case Field::OBJECT_OPPORTUNITY:
// Hubspot has different endpoint for stages
$options = $this->getClient()->fetchOpportunityFieldOptions($field);
break;
case Field::OBJECT_TASK:
if ($field->getCrmProviderId() === 'disposition') {
$options = $this->getClient()->fetchDispositionFieldOptions();
} elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {
$options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);
}
break;
default:
$this->logger->warning('Invalid object type', [
'object_type' => $field->getObjectType(),
'field_id' => $field->getId(),
]);
throw new CrmException('Invalid object type');
}
return $this->importOptions($field, $options);
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
$missingStage = null;
try {
// Use the HubSpot API client instead of the SDK crmPipelines() method
$endpoint = self::getDealsPipelinesEndpoint();
$pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);
$pipelines = $pipelinesResponse->data->results;
} catch (RequestException|BadRequest $exception) {
throw $exception;
}
foreach ($pipelines as $pipeline) {
$stages = [];
// We create a business process to contain the pipeline, and store all stages against it.
$p = ResponseNormalize::normalizePipeline($pipeline);
// Create/update business process for this pipeline
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => $p['active'],
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
// Create/update record type clone
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'is_selectable' => $p['active'],
'business_process_id' => $businessProcess->id ?? null,
]);
// Stages - fetch all existing stages upfront to avoid N+1 queries
$existingStages = $this->config->stages()
->withTrashed()
->where('type', Stage::TYPE_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
foreach ($p['stages'] as $dealStage) {
$s = ResponseNormalize::normalizeDealStage($dealStage);
/** @var ?Stage $existingStage */
$existingStage = $existingStages->get($s['id']);
// Restore soft-deleted stages that are now active in HubSpot
if ($existingStage?->trashed() && $s['active']) {
$existingStage->restore();
}
// Upsert stage (updates soft-deleted records without restoring them)
$stage = $this->config->stages()->withTrashed()->updateOrCreate([
'crm_provider_id' => $s['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($s['label'], 0, 50),
'label' => mb_strimwidth($s['label'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $s['displayOrder'],
'is_selectable' => $s['active'],
'probability' => $s['probability'] * 100,
]);
if ($missingStageName === $s['id']) {
$missingStage = $stage;
}
$stages[] = $stage->id;
}
$businessProcess->stages()->sync($stages);
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
try {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
/** @var array<int, array<string, mixed>> */
return Cache::remember(
key: $this->team->getId() . $name . $count . $offset,
ttl: 300,
callback: function () use ($name, $offset, $count): array {
$data = [];
// Use the new V3 API to find contacts based on additional fields.
foreach (['companies', 'contacts'] as $objectType) {
$payload = $this->generateNameSearchPayload($name, $offset, $count);
$type = $objectType === 'companies' ? 'account' : 'contact';
try {
$response = $this->client->search($objectType, $payload);
// Build mapped list.
foreach ($response['results'] as $object) {
$properties = $object['properties'];
$objectName = $this->buildContactName($properties);
$record = [
'crmId' => $object['id'],
// Pass crmUrl to the FE, needed for success message in the extension when you log activity.
'crmUrl' => $this->generateProviderUrl($object['id'], $type),
'name' => $objectName,
'prospectType' => $type,
'phoneNumbers' => [],
];
if ($type === 'account') {
$record['industry'] = $properties['industry'] ?? null;
} else {
$record['title'] = $properties['jobtitle'] ?? null;
$record['organization'] = $properties['company'] ?? null;
}
$countryCode = $this->buildContactCountry($properties);
$parsedNumber = $this->buildContactPhone($countryCode, $properties);
// Add phone number to record.
if (! empty($parsedNumber['phone'])) {
$record['phoneNumbers'][] = [
'number' => $parsedNumber['phone'],
'nationalFormat' => phone_national($countryCode, $parsedNumber['phone']),
'type' => 'phone',
];
}
// Add mobile phone number to record.
if (! empty($properties['mobilephone'])) {
$mobileNumber = phone_e164($countryCode, $properties['mobilephone']);
if ($mobileNumber !== null) {
$record['phoneNumbers'][] = [
'number' => $mobileNumber,
'nationalFormat' => phone_national($countryCode, $mobileNumber),
'type' => 'mobile',
];
}
}
$data[] = $record;
}
} catch (BadRequest $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->getUuid(),
'request' => $payload,
'reason' => $e->getMessage(),
]);
throw $e;
}
}
return $data;
},
);
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
if ($crmAccountId === null) {
return $data;
}
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
$closedStages = $this->getClosedDealStages();
$payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(
$this->config,
$crmAccountId,
$closedStages,
);
$results = $this->client->getPaginatedData($payload, 'deals');
foreach ($results['results'] as $object) {
$properties = $object['properties'];
$amount = null;
if (empty($properties['amount']) === false) {
$currency = $properties['deal_currency_code'] ?? $this->config->default_currency;
// Values can contain commas and any junk so strip them.
$value = (float) preg_replace('/[^\d.]/', '', $properties['amount']);
$amount = formatCurrency($value, $currency);
}
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
if ($businessProcess === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
} else {
$stage = $businessProcess
->stages()
->where('crm_provider_id', $properties['dealstage'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages(null, $properties['dealstage']);
}
}
$recordType = null;
if ($businessProcess) {
$recordType = $businessProcess->recordTypes()->first();
}
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$record = [
'crmId' => $object['id'],
'name' => $properties['dealname'] ?? 'Unknown Deal',
'value' => $amount,
'won' => $isWon,
'closed' => $isWon || $isLost,
'stage' => [
'id' => $stage?->getUuid() ?? '',
'name' => $stage?->getName() ?? '',
],
];
if ($recordType) {
$record += [
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
}
if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array
{
$data = [];
switch ($objectType) {
case 'contact':
$hsObject = 'contact';
break;
case 'account':
$hsObject = 'company';
break;
default:
// This is a hack to prioritise and override a contact/company with a deal.
if ($opportunityId) {
$hsObject = 'deal';
$objectId = $opportunityId;
} else {
throw new InvalidArgumentException('Object type not supported.');
}
}
$engagementTypes = ['meetings', 'tasks'];
foreach ($engagementTypes as $engagementType) {
$payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);
$this->logger->info('[HubSpot] CRM Search requested', [
'request' => $payload,
]);
$engagements = $this->client->getPaginatedData($payload, $engagementType);
foreach ($engagements['results'] as $engagement) {
if ($engagementType == 'meetings') {
$title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';
} elseif ($engagementType == 'tasks') {
$title = $engagement['properties']['hs_task_subject'];
} else {
$title = 'Scheduled meeting';
}
$data[] = [
'crmId' => $engagement['id'],
'subject' => $title,
'due' => $engagement['properties']['hs_timestamp'],
'type' => $engagement['properties']['hs_activity_type'] ?? null,
];
}
}
usort($data, function ($item1, $item2) {
return $item2['due'] <=> $item1['due'];
});
return $data;
}
/**
* Try to find CRM Objects using email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$contactProperties = [
'email',
'firstname',
'lastname',
'country',
'phone',
'mobilephone',
'jobtitle',
'hubspot_owner_id',
'associatedcompanyid',
'photo',
];
$contact = null;
$account = null;
try {
$hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);
if ($hsContact) {
$contact = $this->importContact($hsContact);
$account = $contact->account;
}
$data = $this->convertCrmData($contact, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
} catch (BadRequest $e) {
$this->logger->warning('[HubSpot] Search failed', [
'team_id' => $this->team->getId(),
'search_identifier' => $email,
'reason' => $e->getMessage(),
]);
}
return null;
}
public function getDomain(string $email): ?string
{
return $this->getDomainFromEmail($email);
}
/**
* Try to find CRM objects using domain name of the email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByDomain(string $domain, ?int $userId = null): ?array
{
$companyName = $domain;
// Try to find a company matching their email domain.
$companyProperties = [
'country',
'phone',
'name',
'hs_avatar_filemanager_key',
'industry',
'hubspot_owner_id',
'domain',
];
try {
$hsAccounts = $this->client
->getInstance()
->companies()
->searchByDomain($companyName, $companyProperties);
} catch (Throwable $e) {
$this->logger->info('[HubSpot] Search failed', [
'error' => $e->getMessage(),
'domain' => $domain,
]);
return null;
}
$account = null;
// If there are multiple accounts, don't guess, we'll ask later.
if (\count($hsAccounts->data->results) === 1) {
// Persist this remote object.
$account = $this->syncAccount($hsAccounts->data->results[0]->companyId);
}
$data = $this->convertCrmData(null, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
}
/**
* @return array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array
{
$countryCode = null;
if ($contact && $contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account && $account->country_code) {
$countryCode = $account->country_code;
}
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
// If there are multiple opportunities, don't guess, we'll ask later.
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
if (str_contains($phone, '**')) {
return null;
}
// trim all whitespaces if present so the lookup doesn't fail
$phone = str_replace(' ', '', $phone);
// Check if the user is internal.
if ($this->isPhoneNumberOfTeamMember($phone)) {
return null;
}
$response = $this->searchForPhoneNumber($phone);
if (empty($response)) {
return null;
}
// This would ideally importContact instead but the response type differs.
$contact = $this->findAndSyncContact($response['results'][0]['id']);
if (! $contact instanceof Contact) {
return null;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
try {
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception $e) {
$this->logger->debug('[HubSpot] Opportunity failed to sync.', [
'reason' => $e->getMessage(),
]);
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
private function isPhoneNumberOfTeamMember(string $phone): bool
{
$teamRepository = app(TeamRepository::class);
$user = $teamRepository->findTeamMemberByPhone($this->team, $phone);
if ($user instanceof User) {
return true;
}
return false;
}
private function findAndSyncContact(string $crmId): ?Contact
{
try {
return $this->syncContact($crmId);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'reason' => $exception->getMessage(),
]);
return null;
}
}
private function hasResults(array $response): bool
{
return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;
}
private function searchForPhoneNumber(string $phone): array
{
// Normalizes the provided phone number for the API search.
$normalizedPhone = $this->normalizePhoneNumber($phone);
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);
$this->logger->info('[HubSpot] Phone match search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);
if (! $this->hasResults($response)) {
$nationalPhone = preg_replace('/\D/', '', phone_national(null, $phone));
$payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);
$this->logger->info('[HubSpot] Phone match national number search triggered', [
'phone' => $phone,
'nationalPhone' => $nationalPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
if (! $this->hasResults($response)) {
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);
$this->logger->info('[HubSpot] Phone match alternative search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
return $this->hasResults($response) ? $response : [];
}
private function handlePhoneSearchRequest(string $phone, array $payload): array
{
try {
return $this->client->search('contacts', $payload);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'phone' => $phone,
'reason' => $exception->getMessage(),
]);
return [];
}
}
private function normalizePhoneNumber(string $phone): string
{
return ltrim(phone_e164(null, $phone), '+0');
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$payload = $this->payloadBuilder->generateSearchContactsByNamePayload(
$name,
$this->getContactFields()
);
$hsContacts = $this->client->getPaginatedData($payload, 'contact');
if (empty($hsContacts['results'])) {
return false;
}
$contact = $this->importContact($hsContacts['results'][0]);
if ($contact === null) {
return false;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
});
return is_array($result) ? $result : null;
}
private function convertActivityAssociations(Activity $activity): array
{
return [
'contactIds' => $this->getParticipantsIds($activity),
'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],
'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],
'ownerIds' => [],
];
}
private function getParticipantsIds(Activity $activity): array
{
$attendees = [];
$participantRepository = app(ParticipantRepository::class);
$participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);
foreach ($participants as $participant) {
if ($participant->user_id || $participant->isCoach()) {
continue;
}
$contact = $participant->contact()->first();
if ($contact && $contact->crm_provider_id) {
$attendees[] = $contact->crm_provider_id;
} else {
if (! empty($participant->name)) {
$attendeeData = $this->fetchMissingAttendeeInfo($participant);
}
if (! empty($attendeeData['id'])) {
$attendees[] = $attendeeData['id'];
}
}
}
if ($activity->hasContact()) {
$attendees[] = $activity->contact->crm_provider_id;
}
return array_unique($attendees);
}
private function fetchMissingAttendeeInfo(Participant $participant): array
{
// Check if we need to look inside an account context.
$activity = $participant->getActivity();
$companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;
// First check the local data.
/** @var Contact[] $contacts */
$contacts = $this->team->contacts()
->with('account')
->where('name', $participant->name)
->whereNotNull('email')
->get();
foreach ($contacts as $contact) {
// If we have a company in scope, check the contact is associated to it.
if (
$companyId !== null
&& ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)
) {
continue;
}
return [
'id' => $contact->crm_provider_id,
'email' => $contact->email,
];
}
$payload = $this->generateNameSearchPayload($participant->name, 0, 20);
try {
$response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);
// TODO add some logic to choose the most suitable contact if multiple
foreach ($response['results'] as $object) {
$properties = $object['properties'];
if (empty($object['properties']) === false) {
// Check the company matches the contact.
// Todo: Move this check inside the API search.
if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {
continue;
}
return [
'id' => $object['id'],
'email' => $properties['email'],
];
}
}
} catch (Exception $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->id_string,
'request' => $payload,
'reason' => $e->getMessage(),
]);
}
return [];
}
/**
* Store transcripts as note engagement.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
// For HS no need to check if Crm profile - Log Notes field is enabled
// We only check if store_transcript toggle is enabled on crm profile.
$engagement = [
'active' => true,
'ownerId' => $this->profile->crm_provider_id,
'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,
'type' => 'NOTE',
];
// Generate activity transcription.
$transcriptionData = $this->generateTranscription($activity);
// Truncate Notes with max notes length because transcription text could be very long.
$transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);
$metadata = [
'body' => $transcripts,
];
$associations = $this->convertActivityAssociations($activity);
try {
$hsEngagement = $this->client
->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
$this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);
$noteId = $hsEngagement->data->engagement->id;
// Store crm logged id in transcription.
$transcription = $activity->getTranscription();
$transcription->crm_activity_id = $noteId;
$transcription->save();
} catch (Exception $e) {
Sentry::captureException($e);
}
}
/*
* @inheritdoc
*/
public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void
{
$payload = [
'properties' => $data,
];
try {
switch ($objectType) {
case FieldData::OBJECT_OPPORTUNITY:
$this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_CONTACT:
$this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_ACCOUNT:
$this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);
break;
case FieldData::OBJECT_TASK:
// Endpoint for Engagements not ready
$engagements = [
'type' => 'TASK',
];
$metadata = $data;
...
|
10162
|
NULL
|
NULL
|
NULL
|
|
10163
|
465
|
4
|
2026-05-08T17:06:54.914265+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260014914_m1.jpg...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Show Replace Field
Search History
doSearch
New Line
Match Case
Words
Regex
Replace History...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"on_screen":true,"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Replace Field","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Search History","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"doSearch","depth":4,"on_screen":true,"value":"doSearch","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Match Case","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Words","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Regex","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Replace History","depth":3,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
5516800432225513958
|
-2904790704783406646
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Show Replace Field
Search History
doSearch
New Line
Match Case
Words
Regex
Replace History...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10162
|
466
|
3
|
2026-05-08T17:06:33.221814+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778259993221_m2.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 3 new items - S Vasil Vasilev (DM) - Jiminny Inc - 3 new items - Slack...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:35 PM
6:05
cursor не зарежда допълннителните таблици
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:07 PM
6:06
ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:16 PM
6:06
което обезмисля цялата гимнастика
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:21 PM
6:06
ще го ревизирам с lazy loading
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:43 PM
6:06
на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
loading…...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.5152925,"top":1.0,"width":0.011968086,"height":-0.058260202},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.5980718,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.61170214,"top":1.0,"width":0.030917553,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.64361703,"top":1.0,"width":0.034242023,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.6788564,"top":1.0,"width":0.020944148,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Pins","depth":17,"bounds":{"left":0.70113033,"top":1.0,"width":0.020279255,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pins","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.7224069,"top":1.0,"width":0.010970744,"height":-0.09177971},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:43 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, привет","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:48 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хвърли моля те едно око тука","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:49 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/app/pull/12059","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/app/pull/12059","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:53:03 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:53","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"опитвам се да оптимизирам процеса по индексиране на активитита за ЕС","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:16 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:35 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:12:58 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:12 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:13:17 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:13","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Switch","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor()","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"lazyById(250)","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":". It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"getIndexableAttributes()","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":") and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:40:06 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:40 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хм, интересна идея","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:03 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го проверя","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:17 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"така или иначе в понеделник ще иде на прод, днес не ми се рискува","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 6:05:10 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"мм, прав си","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:26 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:35 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor не зарежда допълннителните таблици","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:07 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:16 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"което обезмисля цялата гимнастика","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:21 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го ревизирам с lazy loading","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:43 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"loading…","depth":11,"on_screen":false,"role_description":"text"}]...
|
-1984781178899009791
|
-1284830094648227768
|
idle
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:35 PM
6:05
cursor не зарежда допълннителните таблици
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:07 PM
6:06
ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:16 PM
6:06
което обезмисля цялата гимнастика
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:21 PM
6:06
ще го ревизирам с lazy loading
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:43 PM
6:06
на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
loading…
PhostorimcodeFV faVsco.js?9 JY-20725-handle-HS-search-rate-limiProledey(© RemoteCrmobjectmanif © HubspotSyncStrategybase.png€ ResponseNormalize.pheCachedcrmservicebecorator.onpsyncrielaAction.ong© SyncRelatedActivityMar© MatchActivityCrmData.php© CrmActivityService.phgc) MatchermDatc wednooksynebalchrrov O IntegrationAppdosearchx 5 Cc WTIY:>D Accessors>© Api• contiaO DTOW) FiltersM.lobsclass service excenas baseservice znpcemencs903904 CpubLic tunccion matchbybomaln Scring saomain, tinc suseria = nulu: tarrayProspectSearchStrateg)ServiceTraitsC) DataClient.oho© DecorateActivity.php© LocalSearch.phpelocalSearchinterface.of© RemoteSearch.php(C) Service.phpv Ml isteners913© ConvertLeadActivities.p© PurgeLookupCache.php> D MetadataD Migration[ Pipedrive915917>C Fields0 OpportunityMatcher> @ OpportunitySyncStrated921›_ Prospectsearchstrateay>W ServiceTraits925(c) Client.phpc) [EMAIL]) FieldDefinitions.onvC) PavloadBuilder.ohv929930(C) Profile, ohoC) @uervBuilder.ohoC) @uerv.andler.ohoC) @uerviterator nhol9331934(C) @uervRecults.nhn© Service.php(C) SvncRatchRedicServicescompanyname = soomarn'Try to find a company matchina their emall domain.ScompanyProperties = ['hs avatar filemanader key!.try 1ShsAccounts = Sthis->clientl->getInstance->comnaniesol->ceanchRvlomain(ScomnanvName ScomnanvPronenties)•} catch (Throwable $e) {Sthis->logger->info('[HubSpot] Search failed', ['error' => $e->getMessage()D):return nulbSaccount = null:I/ If there are multiple accounts. don'+ quess.we'll ask laterif count(ShsAccounts->data->results) zz= 10 <Persist this remote obiect.Saccount = Sthis->svncAccountShsAccounts->data->results101->comoanv1d0•M Traite© BaseClient.php© BaseService.php(C CachodGrm CorvicaDacoratSdata = Sthis->conventcrmlatald contact: nuil Saccount Susentd)•© CountryCodeResolver.php4) CrmActivitvProviderintegraneturn I emntvlannav filten(Sdata)) ? Sdata • null-rilo May 20:00.33© ProspectCache.phpB7B48 MMSSATATl HI=custom.log ^A SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console [PKou.# console leu)# console [slAGiNg)[2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"neaders".?"Uace":L"Inu,or May 2020 14.21.15 6Ml"Jn"Transter-Encod1nq":"chunked")."Connection":"keep-alive""CF-Ray" : ["9f80deb8db60dc3a-SOF"],"Strict-Transport-Secur1ty":"max-aqe=31536008* 1ncLudeSubDomains: preload")nacceot-encodino""server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\","x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"So+-Cookie"." c+hm-Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtmoV-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To".f"*"endpoints\":[{"unl".httns:la.nel.cloudflane.com./nenon+W/v42c=NVA1cVTPQfVm32anS0#xVF/sd2RN\"group\":\"cf-nel\","max_age\":604800}"]|"NEL": ["1success_traccion.0.01rreportto. "cr-nel,"max age":604800}"]"Server": ["cloudflare"]}} {"correlation_1d":"95256555-ec78-4541-b9za-adta/Sb6Yeab"."trace_10":C/AD8565-905t-4604-9405-0e5b551e5545CascadeHubspot Rate LimitindAskJiminnyReportActivityServiceTest -Hubspot Rate Limit ReInvestigating Rate LinNew CascadeHubspot CRM Call Re- 11I1Actions/SyncArchivedProfilesAction.phpCallVia executeRequest()?Rate Limitapp/Services/Activity/HubSpot/Service.phpThis service uses Sthis=›crmService (the CRM Service.oho))- it makes no direct HubSpot APl calls itselt. All calls delegate through crmservice-›aetcal10, crmService->searchCallsForPeriod(), crmService->syncOpportunity(), crmService->parseRecords() .Critical Findings1. Line 1313 - raw searchApi→>doSearch - matchExactlyByParticipantinService.pno:#Service.oho:1313)Sresponse = sthis->cuient->aetNewinstance->crmo->contactso-searchAoi->doSearchSoavload):• Goes completely around the Client wrapper - no 429 handling, no RateLimitException, no rate limit awareness•Uses the search rate limit bucket• Can be replaced with $this->client-›search('contacts', $payload) - same endpoint, same result, adds 429 protection,tine 020.022-comnandoctl.sconrchRuhorninfl_matchRuDomain/).• Service.php:920-923ShsAccounts = $this->client->getInstance()->companies()->searchByDomain(ScompanyName, ScompanyProperties):• Uses v1 SDK's searchByDomain which calls a search endpoint — hits the search rate limit bucket• No 429 protection• Cannot be trivially replaced with client-›search() (different endpoint/format), but could be wrapped in executeRequest ()2.detdnnortunitvRvldhac executeReauestcommented out.• Client.php:238-239$deal = Sthis->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(• Deliberatelv disabled _ this means sinale deal fetches in HubsootSingleSvncStrateav also aet no 429 protection.Ask anvthina (&4L)Tnl "896-20UITE.Río 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10161
|
465
|
3
|
2026-05-08T17:06:30.917140+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778259990917_m1.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 3 new items - S Vasil Vasilev (DM) - Jiminny Inc - 3 new items - Slack...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:35 PM
6:05
cursor не зарежда допълннителните таблици
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:07 PM
6:06
ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:16 PM
6:06
което обезмисля цялата гимнастика
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:21 PM
6:06
ще го ревизирам с lazy loading
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:43 PM
6:06
на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
loading…...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.51180553,"top":0.08111111,"width":0.025,"height":0.04},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"bounds":{"left":0.50625,"top":0.14,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.5138889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.50625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"bounds":{"left":0.5159722,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.50625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.51111114,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51111114,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.5159722,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.50625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"bounds":{"left":0.51666665,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51666665,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.5208333,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.50625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"bounds":{"left":0.5152778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.50625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"bounds":{"left":0.5152778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.68472224,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.072222225,"height":0.011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.58819443,"top":0.15,"width":0.057638887,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.15,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.59305555,"top":0.15,"width":0.05277778,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.58819443,"top":0.18111111,"width":0.054166667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.58819443,"top":0.21222222,"width":0.034027778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.58819443,"top":0.24333334,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.58819443,"top":0.27444443,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.27444443,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.59444445,"top":0.27444443,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.58819443,"top":0.30555555,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.58819443,"top":0.33666667,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.58819443,"top":0.36777776,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.58819443,"top":0.3988889,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.3988889,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.59305555,"top":0.3988889,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.58819443,"top":0.43,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.58819443,"top":0.4611111,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.58819443,"top":0.49222222,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.49222222,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.5923611,"top":0.49222222,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.58819443,"top":0.5655556,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.5655556,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.59444445,"top":0.5655556,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.58819443,"top":0.5966667,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.58819443,"top":0.62777776,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.58819443,"top":0.6588889,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.6666667,"top":0.6588889,"width":0.013194445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.6715278,"top":0.6588889,"width":0.029861111,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.6715278,"top":0.6588889,"width":0.008333334,"height":0.02}},{"char_start":1,"char_count":13,"bounds":{"left":0.6798611,"top":0.6588889,"width":0.060416665,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.58819443,"top":0.69,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.58819443,"top":0.7211111,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":23,"bounds":{"left":0.58819443,"top":0.75222224,"width":0.016666668,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.58819443,"top":0.78333336,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.58819443,"top":0.8144444,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.58819443,"top":0.84555554,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.65555555,"top":0.84555554,"width":0.013194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.65555555,"top":0.84555554,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":2,"bounds":{"left":0.66041666,"top":0.84555554,"width":0.011805556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.58819443,"top":0.91888887,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.58819443,"top":0.95,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.71319443,"top":0.12777779,"width":0.06458333,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"bounds":{"left":0.7326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.7798611,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.79930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.85347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"bounds":{"left":0.87291664,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.87291664,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.8784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXRadioButton","text":"Pins","depth":17,"bounds":{"left":0.9,"top":0.12777779,"width":0.04236111,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pins","depth":19,"bounds":{"left":0.91944444,"top":0.14,"width":0.017361112,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.9444444,"top":0.12777779,"width":0.022916667,"height":0.04222222},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.8229167,"top":0.17666666,"width":0.05277778,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:43 PM","depth":23,"bounds":{"left":0.8090278,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52 PM","depth":24,"bounds":{"left":0.8090278,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, привет","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.07083333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:48 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хвърли моля те едно око тука","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.14444445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:49 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/app/pull/12059","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/app/pull/12059","depth":25,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:53:03 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:53","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"опитвам се да оптимизирам процеса по индексиране на активитита за ЕС","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.19305556,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:16 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.22638889,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:35 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.22430556,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8111111,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:12:58 PM","depth":23,"bounds":{"left":0.81666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:12 PM","depth":24,"bounds":{"left":0.81666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.23194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:13:17 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:13","depth":25,"bounds":{"left":0.72430557,"top":0.16222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Switch","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.033333335,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor()","depth":25,"bounds":{"left":0.7826389,"top":0.16222222,"width":0.04027778,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to","depth":24,"bounds":{"left":0.82569444,"top":0.16111112,"width":0.015277778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"lazyById(250)","depth":25,"bounds":{"left":0.84305555,"top":0.16222222,"width":0.06527778,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":". It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.22291666,"height":0.09111111},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.9111111,"top":0.15888889,"width":0.0027777778,"height":0.02}},{"char_start":1,"char_count":132,"bounds":{"left":0.7465278,"top":0.15888889,"width":0.22291666,"height":0.093333334}}],"role_description":"text"},{"role":"AXStaticText","text":"getIndexableAttributes()","depth":25,"bounds":{"left":0.74930555,"top":0.26,"width":0.12013889,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":") and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).","depth":24,"bounds":{"left":0.7465278,"top":0.25666666,"width":0.22638889,"height":0.06888889},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.87222224,"top":0.25666666,"width":0.0027777778,"height":0.02}},{"char_start":1,"char_count":108,"bounds":{"left":0.7465278,"top":0.25666666,"width":0.22638889,"height":0.06888889}}],"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.33666667,"width":0.057638887,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.33888888,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:40:06 PM","depth":23,"bounds":{"left":0.8090278,"top":0.3422222,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:40 PM","depth":24,"bounds":{"left":0.8090278,"top":0.3422222,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хм, интересна идея","depth":24,"bounds":{"left":0.7465278,"top":0.36333334,"width":0.093055554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:03 PM","depth":24,"bounds":{"left":0.72430557,"top":0.4,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"bounds":{"left":0.72430557,"top":0.4,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го проверя","depth":24,"bounds":{"left":0.7465278,"top":0.39666668,"width":0.06944445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:17 PM","depth":24,"bounds":{"left":0.72430557,"top":0.43333334,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"bounds":{"left":0.72430557,"top":0.43333334,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"така или иначе в понеделник ще иде на прод, днес не ми се рискува","depth":24,"bounds":{"left":0.7465278,"top":0.43,"width":0.22152779,"height":0.044444446},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.43,"width":0.0055555557,"height":0.02}},{"char_start":1,"char_count":64,"bounds":{"left":0.7465278,"top":0.43,"width":0.22152779,"height":0.044444446}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.48555556,"width":0.057638887,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.48777777,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 6:05:10 PM","depth":23,"bounds":{"left":0.8090278,"top":0.4911111,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05 PM","depth":24,"bounds":{"left":0.8090278,"top":0.4911111,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"мм, прав си","depth":24,"bounds":{"left":0.7465278,"top":0.51222223,"width":0.055555556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:26 PM","depth":24,"bounds":{"left":0.72430557,"top":0.54888886,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"bounds":{"left":0.72430557,"top":0.54888886,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем","depth":24,"bounds":{"left":0.7465278,"top":0.54555553,"width":0.22291666,"height":0.044444446},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.54555553,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":71,"bounds":{"left":0.7465278,"top":0.54555553,"width":0.22222222,"height":0.044444446}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:35 PM","depth":24,"bounds":{"left":0.72430557,"top":0.6066667,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"bounds":{"left":0.72430557,"top":0.6066667,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor не зарежда допълннителните таблици","depth":24,"bounds":{"left":0.7465278,"top":0.60333335,"width":0.21944444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.5688889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.5688889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.5688889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.5688889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:07 PM","depth":24,"bounds":{"left":0.72430557,"top":0.64,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"bounds":{"left":0.72430557,"top":0.64,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало","depth":24,"bounds":{"left":0.7465278,"top":0.63666666,"width":0.23472223,"height":0.06888889},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.63666666,"width":0.009027778,"height":0.02}},{"char_start":1,"char_count":107,"bounds":{"left":0.7465278,"top":0.63666666,"width":0.23472223,"height":0.06888889}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.6022222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.6022222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.6022222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.6022222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:16 PM","depth":24,"bounds":{"left":0.72430557,"top":0.7222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"bounds":{"left":0.72430557,"top":0.7222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"което обезмисля цялата гимнастика","depth":24,"bounds":{"left":0.7465278,"top":0.7188889,"width":0.17569445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.6844444,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.6844444,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.6844444,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.6844444,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:21 PM","depth":24,"bounds":{"left":0.72430557,"top":0.75555557,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"bounds":{"left":0.72430557,"top":0.75555557,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го ревизирам с lazy loading","depth":24,"bounds":{"left":0.7465278,"top":0.75222224,"width":0.14513889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.7177778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.7177778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.7177778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.7177778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:43 PM","depth":24,"bounds":{"left":0.72430557,"top":0.7888889,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"bounds":{"left":0.72430557,"top":0.7888889,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти","depth":24,"bounds":{"left":0.7465278,"top":0.78555554,"width":0.23194444,"height":0.06888889},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.78555554,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":90,"bounds":{"left":0.7465278,"top":0.78555554,"width":0.23194444,"height":0.06888889}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.7511111,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.7511111,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.7511111,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.7511111,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"bounds":{"left":0.71666664,"top":0.88,"width":0.26527777,"height":0.04222222},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"loading…","depth":11,"on_screen":false,"role_description":"text"}]...
|
-1984781178899009791
|
-1284830094648227768
|
idle
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:35 PM
6:05
cursor не зарежда допълннителните таблици
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:07 PM
6:06
ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:16 PM
6:06
което обезмисля цялата гимнастика
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:21 PM
6:06
ще го ревизирам с lazy loading
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:43 PM
6:06
на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
loading…
SlackFileEditViewGoHistoryWindowHelpLukás Koválik's No...ProGPHubspot API calls+n Home1000TestDailyAgents+ New agentWorkspace* Quick NoteWorkJira ticketView of SprintDailyPlanSprintStefka 1-1TododevEvaluationKnowledgera IdeasPrivateE Home viewsIntegration-appWork KnowledgeWork Knowledgetesting keyboard4Todo2 New chat x03 Hubspot / Hubspot API callsCritical Findings1. Line 1313 - rawsearchApi()->doSearch()- matchExSresponse = Sthis->client->getNewInstance()->crm(• Goes completely around the Client wrapper - no 429• Uses the search rate limit bucket• Can be replaced with $this->client->search('contacts"2. Line 920-923 — companies()->searchByDomain() - m$hsAccounts = $this->client->getInstance()->compai• Uses v1 SDK's searchByDomainwhich calls a search e• No 429 protection• Cannot be trivially replaced with client->search() (diffePress 'space' for Al or 'l' for commands40QHomeDMsActivityFilesLater...MoreED→Jiminny... v# conrusion-cHnic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Direct messagesSo Vasil VasilevNikolay IvanovGalya DimitrovaAneliya Angelova, ...2 Stoyan Tanev €ã. Stefka StoyanovaC. Ves. Aneliya Angelovado James GrahamLukas Kovalik y... O#:: AppsToastJira Cloudlabl100% <•Fri 8 May 20:06:31Describe what you are looking forVasil Vasilev• MessagesAdd canvasO Files< Pins+carsoro to Lazyoysa(couyele prescivesthe single-loop, gToday~-yle code in the newversion while restoring proper batched eagerloading (avoiding N+1 ongetIndexableAttributes ) and releasing the DBconnection between chunks (avoiding long-heldPDO connections during ES/Sentry calls).Vasil Vasilev 4:40 PMхм, интересна идеяще го проверятака или иначе в понеделник ще иде на прод.днес не ми се рискуваVasil Vasilev 6:05 PMмм, прав сизадълбах по на дълбоко, и се оказва, че cursorще произведе друг проблемcursor не зарежда допьлннителните таблицище стриймне моделите, но за всеки ще викапоотделно with(opportunities, leads, accounts....) ивсичко останалокоето обезмисля цялата гимнастикаще го ревизирам с lazy loadingна по малки бачове, за да спестя памет отмоделите, просто ще взема данните на няколкопЪтиMessage Vasil Vasilev+...
|
10159
|
NULL
|
NULL
|
NULL
|
|
10160
|
466
|
2
|
2026-05-08T17:06:00.112348+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778259960112_m2.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 3 new items - S Vasil Vasilev (DM) - Jiminny Inc - 3 new items - Slack...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:35 PM
6:05
cursor не зарежда допълннителните таблици
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:07 PM
6:06
ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:16 PM
6:06
което обезмисля цялата гимнастика
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:21 PM
6:06
ще го ревизирам с lazy loading
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:43 PM
6:06
на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.5152925,"top":1.0,"width":0.011968086,"height":-0.058260202},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.5980718,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.61170214,"top":1.0,"width":0.030917553,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.64361703,"top":1.0,"width":0.034242023,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.6788564,"top":1.0,"width":0.020944148,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Pins","depth":17,"bounds":{"left":0.70113033,"top":1.0,"width":0.020279255,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pins","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.7224069,"top":1.0,"width":0.010970744,"height":-0.09177971},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:43 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, привет","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:48 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хвърли моля те едно око тука","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:49 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/app/pull/12059","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/app/pull/12059","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:53:03 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:53","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"опитвам се да оптимизирам процеса по индексиране на активитита за ЕС","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:16 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:35 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:12:58 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:12 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:13:17 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:13","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Switch","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor()","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"lazyById(250)","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":". It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"getIndexableAttributes()","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":") and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:40:06 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:40 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хм, интересна идея","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:03 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го проверя","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:17 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"така или иначе в понеделник ще иде на прод, днес не ми се рискува","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 6:05:10 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"мм, прав си","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:26 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:35 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor не зарежда допълннителните таблици","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:07 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:16 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"което обезмисля цялата гимнастика","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:21 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го ревизирам с lazy loading","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:43 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-1432458227809580954
|
-1284830094648227768
|
idle
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:35 PM
6:05
cursor не зарежда допълннителните таблици
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:07 PM
6:06
ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:16 PM
6:06
което обезмисля цялата гимнастика
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:21 PM
6:06
ще го ревизирам с lazy loading
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:43 PM
6:06
на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
PhostorimcodeFV faVsco.js?9 JY-20725-handle-HS-search-rate-limiProledey(© RemoteCrmobjectmanif © HubspotSyncStrategybase.png€ ResponseNormalize.pheCachedcrmservicebecorator.onp© syncrielaAction.ong© SyncRelatedActivityMar© MatchActivityCrmData.php© CrmActivityService.phgc) MatchermDatc wednooksynebalchrrov O IntegrationAppdosearchx 5 Cc WTIY:>D Accessors>© Api• contiaO DTOW) FiltersM.lobsclass service excenas baseservice znpcemencs903904 CpubLic tunccion matchbybomaln Scring saomain, tinc suseria = nulu: tarrayProspectSearchStrateg)ServiceTraitsC) DataClient.oho© DecorateActivity.php© LocalSearch.php© LocalSearchinterface.pt© RemoteSearch.php(C) Service.phpv Ml isteners913© ConvertLeadActivities.p© PurgeLookupCache.php> D MetadataD Migration[ Pipedrive915917>C FieldsC OpportunityMatcher> @ OpportunitySyncStrated921›_ Prospectsearchstrateay>W ServiceTraits925(c) Client.phpc) [EMAIL]) FieldDefinitions.onvC) PavloadBuilder.ohv929930(C) Profile, ohoC) @uervBuilder.ohoC) @uerv.andler.ohoC) @uerviterator nhol9331934(C) @uervRecults.nhn© Service.php(C) SvncRatchRedicServicescompanyname = soomarn'Try to find a company matchina their emall domain.ScompanyProperties = ['hs avatar filemanader key!.try 1ShsAccounts = Sthis->clientl->getInstance->comnaniesol->ceanchRvlomain(ScomnanvName ScomnanvPronenties)•} catch (Throwable $e) {Sthis->logger->info('[HubSpot] Search failed', ['error' => $e->getMessage()D):return nulbSaccount = null:I/ If there are multiple accounts. don'+ quess.we'll ask laterif count(ShsAccounts->data->results) zz= 10 <Persist this remote obiect.Saccount = Sthis->svncAccountShsAccounts->data->results101->comoanv1d0•M Traite© BaseClient.php© BaseService.php(C CachodGrm CorvicaDacoratSdata = Sthis->conventcrmlatald contact: nuil Saccount Susentd)•© CountryCodeResolver.php4) CrmActivitvProviderintegraneturn I emntvlannav filten(Sdata)) ? Sdata • null-rilo May 20:00.0© ProspectCache.phpB7B48 MMSSATATl HI=custom.log ^4 SF (jiminny@localhost]4 HS_local [jiminny@localhost]# console [PKou.# console leu)# console [slAGiNg)[2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"neaders".?"Uace":L"Inu,or May 2020 14.21.15 6Ml"Jn"Transter-Encod1nq":"chunked")."Connection":"keep-alive""CF-Ray" : ["9f80deb8db60dc3a-SOF"],"Strict-Transport-Secur1ty":"max-aqe=31536008* 1ncLudeSubDomains: preload")nacceot-encodino""server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\","x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"So+-Cookie"." c+hm-Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtmoV-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To".f"*"endpoints\":[{"unl".httns:la.nel.cloudflane.com./nenon+W/v42c=NVA1cVTPQfVm32anS0#xVF/sd2RN\"group\":\"cf-nel\","max_age\":604800}"]|"NEL": ["1success_traccion.0.01rreportto. "cr-nel,"max age":604800}"]"Server": ["cloudflare"]}} {"correlation_1d":"95256555-ec78-4541-b9za-adta/Sb6Yeab"."trace_10":C/AD8565-905t-4604-9405-0e5b551e5545CascadeHubspot Rate LimitindAskJiminnyReportActivityServiceTest -Hubspot Rate Limit ReInvestigating Rate LinNew CascadeHubspot CRM Call Re- 11I1Actions/SyncArchivedProfilesAction.phpCallVia executeRequest()?Rate Limitapp/Services/Activity/HubSpot/Service.phpThis service uses Sthis=›crmService (the CRM Service.oho))- it makes no direct HubSpot APl calls itselt. All calls delegate through crmservice-›aetcal10, crmService->searchCallsForPeriod(), crmService->syncOpportunity(), crmService->parseRecords() .Critical Findings1. Line 1313 - raw searchApi→>doSearch - matchExactlyByParticipantinService.pno:#Service.oho:1313)Sresponse = sthis->cuient->aetNewinstance->crmo->contactso-searchAoi->doSearchSoavload):• Goes completely around the Client wrapper - no 429 handling, no RateLimitException, no rate limit awareness•Uses the search rate limit bucket• Can be replaced with $this->client-›search('contacts', $payload) - same endpoint, same result, adds 429 protection,tine 020.022-comnandoctl.sconrchRuhorninfl_matchRuDomain/).• Service.php:920-923ShsAccounts = $this->client->getInstance()->companies()->searchByDomain(ScompanyName, ScompanyProperties):• Uses v1 SDK's searchByDomain which calls a search endpoint — hits the search rate limit bucket• No 429 protection• Cannot be trivially replaced with client-›search() (different endpoint/format), but could be wrapped in executeRequest ()2.detdnnortunitvRvldhac executeReauestcommented out.• Client.php:238-239$deal = Sthis->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(• Deliberatelv disabled _ this means sinale deal fetches in HubsootSingleSvncStrateav also aet no 429 protection.Ask anvthina (&4L)Tnl "896-20UITE.Río 4 spaces...
|
10158
|
NULL
|
NULL
|
NULL
|
|
10159
|
465
|
2
|
2026-05-08T17:05:59.140403+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778259959140_m1.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 3 new items - S Vasil Vasilev (DM) - Jiminny Inc - 3 new items - Slack...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.51180553,"top":0.08111111,"width":0.025,"height":0.04},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"bounds":{"left":0.50625,"top":0.14,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.5138889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.50625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"bounds":{"left":0.5159722,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.50625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.51111114,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51111114,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.5159722,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.50625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"bounds":{"left":0.51666665,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51666665,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.5208333,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.50625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"bounds":{"left":0.5152778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.50625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"bounds":{"left":0.5152778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.68472224,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.072222225,"height":0.011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.58819443,"top":0.15,"width":0.057638887,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.15,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.59305555,"top":0.15,"width":0.05277778,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.58819443,"top":0.18111111,"width":0.054166667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.58819443,"top":0.21222222,"width":0.034027778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.58819443,"top":0.24333334,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.58819443,"top":0.27444443,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.27444443,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.59444445,"top":0.27444443,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.58819443,"top":0.30555555,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.58819443,"top":0.33666667,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.58819443,"top":0.36777776,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.58819443,"top":0.3988889,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.3988889,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.59305555,"top":0.3988889,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.58819443,"top":0.43,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.58819443,"top":0.4611111,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.58819443,"top":0.49222222,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.49222222,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.5923611,"top":0.49222222,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.58819443,"top":0.5655556,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.5655556,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.59444445,"top":0.5655556,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.58819443,"top":0.5966667,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.58819443,"top":0.62777776,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.58819443,"top":0.6588889,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.6666667,"top":0.6588889,"width":0.013194445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.6715278,"top":0.6588889,"width":0.029861111,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.6715278,"top":0.6588889,"width":0.008333334,"height":0.02}},{"char_start":1,"char_count":13,"bounds":{"left":0.6798611,"top":0.6588889,"width":0.060416665,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.58819443,"top":0.69,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.58819443,"top":0.7211111,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":23,"bounds":{"left":0.58819443,"top":0.75222224,"width":0.016666668,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.58819443,"top":0.78333336,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.58819443,"top":0.8144444,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.58819443,"top":0.84555554,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.65555555,"top":0.84555554,"width":0.013194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.65555555,"top":0.84555554,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":2,"bounds":{"left":0.66041666,"top":0.84555554,"width":0.011805556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.58819443,"top":0.91888887,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.58819443,"top":0.95,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.71319443,"top":0.12777779,"width":0.06458333,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"bounds":{"left":0.7326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.7798611,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.79930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.85347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"bounds":{"left":0.87291664,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.87291664,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.8784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXRadioButton","text":"Pins","depth":17,"bounds":{"left":0.9,"top":0.12777779,"width":0.04236111,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pins","depth":19,"bounds":{"left":0.91944444,"top":0.14,"width":0.017361112,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.9444444,"top":0.12777779,"width":0.022916667,"height":0.04222222},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.8229167,"top":0.17666666,"width":0.05277778,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:43 PM","depth":23,"bounds":{"left":0.8090278,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52 PM","depth":24,"bounds":{"left":0.8090278,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, привет","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.07083333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:48 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хвърли моля те едно око тука","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.14444445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:49 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/app/pull/12059","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/app/pull/12059","depth":25,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:53:03 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:53","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"опитвам се да оптимизирам процеса по индексиране на активитита за ЕС","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.19305556,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:16 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.22638889,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:35 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.22430556,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8111111,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:12:58 PM","depth":23,"bounds":{"left":0.81666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:12 PM","depth":24,"bounds":{"left":0.81666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.23194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:13:17 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:13","depth":25,"bounds":{"left":0.72430557,"top":0.16222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Switch","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.033333335,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor()","depth":25,"bounds":{"left":0.7826389,"top":0.16222222,"width":0.04027778,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to","depth":24,"bounds":{"left":0.82569444,"top":0.16111112,"width":0.015277778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"lazyById(250)","depth":25,"bounds":{"left":0.84305555,"top":0.16222222,"width":0.06527778,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":". It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.22291666,"height":0.09111111},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.9111111,"top":0.15888889,"width":0.0027777778,"height":0.02}},{"char_start":1,"char_count":132,"bounds":{"left":0.7465278,"top":0.15888889,"width":0.22291666,"height":0.093333334}}],"role_description":"text"},{"role":"AXStaticText","text":"getIndexableAttributes()","depth":25,"bounds":{"left":0.74930555,"top":0.26,"width":0.12013889,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":") and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).","depth":24,"bounds":{"left":0.7465278,"top":0.25666666,"width":0.22638889,"height":0.06888889},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.87222224,"top":0.25666666,"width":0.0027777778,"height":0.02}},{"char_start":1,"char_count":108,"bounds":{"left":0.7465278,"top":0.25666666,"width":0.22638889,"height":0.06888889}}],"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.33666667,"width":0.057638887,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.33888888,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:40:06 PM","depth":23,"bounds":{"left":0.8090278,"top":0.3422222,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:40 PM","depth":24,"bounds":{"left":0.8090278,"top":0.3422222,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хм, интересна идея","depth":24,"bounds":{"left":0.7465278,"top":0.36333334,"width":0.093055554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:03 PM","depth":24,"bounds":{"left":0.72430557,"top":0.4,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"bounds":{"left":0.72430557,"top":0.4,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го проверя","depth":24,"bounds":{"left":0.7465278,"top":0.39666668,"width":0.06944445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:17 PM","depth":24,"bounds":{"left":0.72430557,"top":0.43333334,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"bounds":{"left":0.72430557,"top":0.43333334,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"така или иначе в понеделник ще иде на прод, днес не ми се рискува","depth":24,"bounds":{"left":0.7465278,"top":0.43,"width":0.22152779,"height":0.044444446},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.43,"width":0.0055555557,"height":0.02}},{"char_start":1,"char_count":64,"bounds":{"left":0.7465278,"top":0.43,"width":0.22152779,"height":0.044444446}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.48555556,"width":0.057638887,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.48777777,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 6:05:10 PM","depth":23,"bounds":{"left":0.8090278,"top":0.4911111,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05 PM","depth":24,"bounds":{"left":0.8090278,"top":0.4911111,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"мм, прав си","depth":24,"bounds":{"left":0.7465278,"top":0.51222223,"width":0.055555556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:26 PM","depth":24,"bounds":{"left":0.72430557,"top":0.54888886,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"bounds":{"left":0.72430557,"top":0.54888886,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем","depth":24,"bounds":{"left":0.7465278,"top":0.54555553,"width":0.22291666,"height":0.044444446},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.54555553,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":71,"bounds":{"left":0.7465278,"top":0.54555553,"width":0.22222222,"height":0.044444446}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7888038332040964155
|
-1208268909610629012
|
idle
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
SlackFileEditViewGoHistoryWindowHelpLukás Koválik's No...ProGPHubspot API calls+n Home1000TestDailyAgents+ New agentWorkspace* Quick NoteWorkJira ticketView of SprintDailyPlanSprintStefka 1-1TododevEvaluationKnowledgera IdeasPrivateE Home viewsIntegration-appWork KnowledgeWork Knowledgetesting keyboard4Todo2 New chat x03 Hubspot / Hubspot API callsCritical Findings1. Line 1313 - rawsearchApi()->doSearch()- matchExSresponse = Sthis->client->getNewInstance()->crm(• Goes completely around the Client wrapper - no 429• Uses the search rate limit bucket• Can be replaced with $this->client->search('contacts"2. Line 920-923 — companies()->searchByDomain() - m$hsAccounts = $this->client->getInstance()->compai• Uses v1 SDK's searchByDomainwhich calls a search e• No 429 protection• Cannot be trivially replaced with client->search() (diffePress 'space' for Al or 'l' for commands40QHomeDMsActivityFilesLater...MoreED→Jiminny... v# conrusion-cHnic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Direct messagesSo Vasil VasilevNikolay IvanovGalya DimitrovaAneliya Angelova, ...2 Stoyan Tanev €ã. Stefka StoyanovaC. Ves. Aneliya Angelovado James GrahamLukas Kovalik y... O#:: AppsToastJira Cloudlabl100% <•Fri 8 May 20:05:59Describe what you are looking forVasil Vasilev• MessagesAdd canvasO Files< Pins+carsoro to Lazyoysa(couyele prescivesthe single-loop, gToday~-yle code in the newversion while restoring proper batched eagerloading (avoiding N+1 ongetIndexableAttributes ) and releasing the DBconnection between chunks (avoiding long-heldPDO connections during ES/Sentry calls).Vasil Vasilev 4:40 PMхм, интересна идеяще го проверятака или иначе в понеделник ще иде на прод.днес не ми се рискуваVasil Vasilev 6:05 PMмм, прав сизадълбах по на дълбоко, и се оказва, че cursorще произведе друг проблемcursor не зарежда допьлннителните таблицище стриймне моделите, но за всеки ще викапоотделно with(opportunities, leads, accounts....) ивсичко останалокоето обезмисля цялата гимнастикаще го ревизирам с lazy loadingна по малки бачове, за да спестя памет отмоделите, просто ще взема данните на няколкопЪтиMessage Vasil Vasilev+...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10158
|
466
|
1
|
2026-05-08T17:05:27.532501+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778259927532_m2.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 3 new items - S Vasil Vasilev (DM) - Jiminny Inc - 3 new items - Slack...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Apr 28th at 4:53:41 PM
4:53 PM
ок, ще питам Вес, мерси
Vasil Vasilev
Apr 28th at 5:00:16 PM
5:00 PM
моля
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:35 PM
6:05
cursor не зарежда допълннителните таблици
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:07 PM
6:06
ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:16 PM
6:06
което обезмисля цялата гимнастика
Today at 6:06:21 PM
6:06
ще го ревизирам с lazy loading
Today at 6:06:43 PM
6:06
на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти
loading…...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.5152925,"top":1.0,"width":0.011968086,"height":-0.058260202},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.5980718,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.61170214,"top":1.0,"width":0.030917553,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.64361703,"top":1.0,"width":0.034242023,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.6788564,"top":1.0,"width":0.020944148,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Pins","depth":17,"bounds":{"left":0.70113033,"top":1.0,"width":0.020279255,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pins","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.7224069,"top":1.0,"width":0.010970744,"height":-0.09177971},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 4:53:41 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:53 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ок, ще питам Вес, мерси","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:00:16 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:00 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"моля","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:43 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, привет","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:48 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хвърли моля те едно око тука","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:49 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/app/pull/12059","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/app/pull/12059","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:53:03 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:53","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"опитвам се да оптимизирам процеса по индексиране на активитита за ЕС","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:16 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:35 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:12:58 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:12 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:13:17 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:13","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Switch","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor()","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"lazyById(250)","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":". It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"getIndexableAttributes()","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":") and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:40:06 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:40 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хм, интересна идея","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:03 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го проверя","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:17 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"така или иначе в понеделник ще иде на прод, днес не ми се рискува","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 6:05:10 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"мм, прав си","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:26 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:35 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor не зарежда допълннителните таблици","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:07 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:16 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"което обезмисля цялата гимнастика","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 6:06:21 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ще го ревизирам с lazy loading","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 6:06:43 PM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXTextArea","text":"","depth":23,"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"loading…","depth":11,"on_screen":false,"role_description":"text"}]...
|
-1055750629588252217
|
-1284830094511912868
|
idle
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Apr 28th at 4:53:41 PM
4:53 PM
ок, ще питам Вес, мерси
Vasil Vasilev
Apr 28th at 5:00:16 PM
5:00 PM
моля
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:35 PM
6:05
cursor не зарежда допълннителните таблици
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:07 PM
6:06
ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:16 PM
6:06
което обезмисля цялата гимнастика
Today at 6:06:21 PM
6:06
ще го ревизирам с lazy loading
Today at 6:06:43 PM
6:06
на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти
loading…
PhostorimcodeFV faVsco.js?9 JY-20725-handle-HS-search-rate-limiProledey(© RemoteCrmobjectmanif © HubspotSyncStrategybase.png€ ResponseNormalize.phrCachedcrmservicebecorator.onpsyncrielaAction.ong© SyncRelatedActivityMar© MatchActivityCrmData.php© CrmActivityService.phgc) MatchermDatc wednooksynebalchrrov O IntegrationAppdosearchx 5 Cc wTIY:>D Accessors>© Api• contiaO DTOW) FiltersM.lobsclass service excenas baseservice znpcemencs903904 CpubLic tunccion matchbybomaln Scring saomain, tinc suseria = nulu: tarrayProspectSearchStrateg)ServiceTraitsC) DataClient.oho© DecorateActivity.php© [EMAIL]© RemoteSearch.php(C) Service.php913v Ml isteners© ConvertLeadActivities.p© PurgeLookupCache.php> D MetadataD Migration[ Pipedrive915917>C FieldsC OpportunityMatcher> @ OpportunitySyncStrated921_Prospectsearchstrateay>W ServiceTraits925(c) Client.phpc) [EMAIL]) FieldDefinitions.onvC) PavloadBuilder.ohv929930(C) Profile, ohoC) @uervBuilder.ohoC) @uerv.andler.ohoC) @uerviterator nhol9331934(C) @uervRecults.nhn© Service.php(C) SvncRatchRedicServicescompanyname = soomarn'Try to find a company matchina their emall domain.ScompanyProperties = ['hs avatar filemanader key!.try 1ShsAccounts = Sthis->clientl->getInstance->comnaniesol->ceanchRvlomain(ScomnanvName ScomnanvPronenties)•} catch (Throwable $e) {Sthis->logger->info('[HubSpot] Search failed', ["error = se->gethessageD):return nulbSaccount = null:I/ If there are multiple accounts. don'+ quess.we'll ask laterif count(ShsAccounts->data->results) zz= 10 <Persist this remote obiect.Saccount = Sthis->svncAccountShsAccounts->data->results101->comoanv1d0•M Traite© BaseClient.php© BaseService.php(C CachodGrm CorvicaDacaratSdata = Sthis->conventcrmlatald contact: nuil Saccount Susentd)•© CountryCodeResolver.phpneturn I emntvlannav filten(Sdata)) ? Sdata • null-4) CrmActivitvProviderintegrariio May 20:00.41© ProspectCache.php=custom.log ^A SF (jiminny@localhost]4 HS_local [jiminny@localhost]# console [PKou.# console leu)# console [slAGiNg)[2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"neaders".?"Uace":L"Inu,or May 2020 14.21.15 6Ml"Jn"Transter-Encod1nq":"chunked")."Connection":"keep-alive""CF-Ray" : ["9f80deb8db60dc3a-SOF"],"Strict-Transport-Secur1ty":"max-aqe=31536008* 1ncLudeSubDomains: preload")nacceot-encodino""server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\","x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"So+-Cookie"." c+hm-Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtmoV-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To".f"*"endpoints\":[{"unl".httns:la.nel.cloudflane.com./nenon+W/v42c=NVA1cVTPQfVm32anS0#xVF/sd2RN\"group\":\"cf-nel\","max_age\":604800}"]|"NEL":["{success_traccion.0.01rreportto. "cr-nel,"max age":604800}"]"Server": ["cloudflare"]}} {"correlation_1d":"95256555-ec78-4541-b9za-adta/Sb6Yeab"."trace_10":C/AD8565-905t-4604-9405-0e5b551e5545CascadeHubspot Rate LimitindAskJiminnyReportActivityServiceTest -Hubspot Rate Limit ReInvestigating Rate LinNew CascadeHubspot CRM Call ReActions/SyncArchivedProfilesAction.phpCallVia executeRequest()?Rate Limitapp/Services/Activity/HubSpot/Service.phpThis service uses Sthis=›crmService (the CRM Service.oho))- it makes no direct HubSpot APl calls itselt. All calls delegate through crmservice-›aetcal10, crmService->searchCallsForPeriod(), crmService->syncOpportunity(), crmService->parseRecords() .Critical Findings1. Line 1313 - raw searchApi→>doSearch - matchExactlyByParticipantinService.pno:#Service.oho:1313)Sresponse = sthis->cuient->aetNewinstance->crmo->contactso-searchAoi->doSearchSoavload):• Goes completely around the Client wrapper - no 429 handling, no RateLimitException, no rate limit awareness•Uses the search rate limit bucket• Can be replaced with $this->client-›search('contacts', $payload) - same endpoint, same result, adds 429 protection,tine 020.022-comnandoctl.sconrchRuhorninfl_matchRuDomain/).• Service.php:920-923ShsAccounts = $this->client->getInstance()->companies()->searchByDomain(ScompanyName, ScompanyProperties):• Uses v1 SDK's searchByDomain which calls a search endpoint — hits the search rate limit bucket• No 429 protection• Cannot be trivially replaced with client-›search() (different endpoint/format), but could be wrapped in executeRequest ()2.detdnnortunitvRvldhac executeReauestcommented out.• Client.php:238-239$deal = Sthis->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(• Deliberatelv disabled _ this means sinale deal fetches in HubsootSingleSvncStrateav also aet no 429 protection.Ask anvthina (&4L)Tnl "896-20UITE.Rfo 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10157
|
465
|
1
|
2026-05-08T17:05:24.890541+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778259924890_m1.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 3 new items - S Vasil Vasilev (DM) - Jiminny Inc - 3 new items - Slack...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.51180553,"top":0.08111111,"width":0.025,"height":0.04},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"bounds":{"left":0.50625,"top":0.14,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.5138889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.50625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"bounds":{"left":0.5159722,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.50625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.51111114,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51111114,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.5159722,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.50625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"bounds":{"left":0.51666665,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51666665,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.5208333,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.50625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"bounds":{"left":0.5152778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.50625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"bounds":{"left":0.5152778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.68472224,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.072222225,"height":0.011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.58819443,"top":0.15,"width":0.057638887,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.15,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.59305555,"top":0.15,"width":0.05277778,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.58819443,"top":0.18111111,"width":0.054166667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.58819443,"top":0.21222222,"width":0.034027778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.58819443,"top":0.24333334,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.58819443,"top":0.27444443,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.27444443,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.59444445,"top":0.27444443,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.58819443,"top":0.30555555,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.58819443,"top":0.33666667,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.58819443,"top":0.36777776,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.58819443,"top":0.3988889,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.3988889,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.59305555,"top":0.3988889,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.58819443,"top":0.43,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.58819443,"top":0.4611111,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.58819443,"top":0.49222222,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.49222222,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.5923611,"top":0.49222222,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.58819443,"top":0.5655556,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.5655556,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.59444445,"top":0.5655556,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.58819443,"top":0.5966667,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.58819443,"top":0.62777776,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.58819443,"top":0.6588889,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.6666667,"top":0.6588889,"width":0.013194445,"height":0.02},"on_screen":true,"role_description":"text"}]...
|
-6622950284457258941
|
-5783504010484244825
|
visual_change
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
SlackFileEditViewGoHistoryWindowHelpLukás Koválik's No...ProGPHubspot API calls+n Home1000TestDailyAgents+ New agentWorkspace* Quick NoteWorkJira ticketView of SprintDailyPlanSprintStefka 1-1TododevEvaluationKnowledgera IdeasPrivateE Home viewsIntegration-appWork KnowledgeWork Knowledgetesting keyboard4Todo2 New chat x03 Hubspot / Hubspot API callsCritical Findings1. Line 1313 - rawsearchApi()->doSearch()- matchExlSresponse = Sthis->client->getNewInstance()->crm(• Goes completely around the Client wrapper - no 429• Uses the search rate limit bucket• Can be replaced with $this->client->search('contacts"2. Line 920-923 — companies()->searchByDomain() - m$hsAccounts = $this->client->getInstance()->compai• Uses v1 SDK's searchByDomainwhich calls a search e• No 429 protection• Cannot be trivially replaced with client->search() (diffePress 'space' for Al or 'l' for commandsHomeDMsActivityFilesLater...MoreED→Jiminny... v# conrusion-cHnic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Direct messagesSo Vasil Vasilevo Nikolay IvanovGalya DimitrovaAneliya Angelova, ...2 Stoyan Tanev €ã. Stefka StoyanovaC. Ves. Aneliya Angelovado James GrahamLukas Kovalik y...#:: AppsToastJira Cloud40100% <•Fri 8 May 20:05:27QDescribe what you are looking forVasil Vasilev6 0• Messagest* Add canvasO Files< Pins+да се генерира еToday ~* 100 активититаи после да увелича размера на бачовете, за даимаме по малко blocking операции в ЕС, катореиндексир-99 HLukas Koval!здрасти, изглежда ок, но когато го минах и презgemini ми даде един warning.Switch cursor() to lazyById(250) . It preservesthe single-loop, generator-style code in the newversion while restoring proper batched eagerloading (avoiding N+1 ongetIndexableAttributes) ) and releasing the DBconnection between chunks (avoiding long-heldPDO connections during ES/Sentry calls).Vasil Vasilev 4:40 PMхм, интересна идеяще го проверятака или иначе в понеделник ще иде на прод,днес не ми се рискуваVasil Vasilev 6:05 PMмм, прав сизадълбах по на дълбоко, и се оказва, че cursorще произведе друг проблемcursor не зарежда допълннителните таблицище стриймне моделите, но за всеки ще викаMessage Vasil Vasilev+...
|
10156
|
NULL
|
NULL
|
NULL
|
|
10155
|
466
|
0
|
2026-05-08T17:04:49.843268+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778259889843_m2.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 3 new items - S Vasil Vasilev (DM) - Jiminny Inc - 3 new items - Slack...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:35 PM
6:05
cursor не зарежда допълннителните таблици
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:07 PM
6:06
ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:16 PM
6:06
което обезмисля цялата гимнастика
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:21 PM
6:06
ще го ревизирам с lazy loading
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:43 PM
6:06
на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.5152925,"top":1.0,"width":0.011968086,"height":-0.058260202},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.5980718,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.61170214,"top":1.0,"width":0.030917553,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.64361703,"top":1.0,"width":0.034242023,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.6788564,"top":1.0,"width":0.020944148,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Pins","depth":17,"bounds":{"left":0.70113033,"top":1.0,"width":0.020279255,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pins","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.7224069,"top":1.0,"width":0.010970744,"height":-0.09177971},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:43 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, привет","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:48 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хвърли моля те едно око тука","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:49 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/app/pull/12059","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/app/pull/12059","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:53:03 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:53","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"опитвам се да оптимизирам процеса по индексиране на активитита за ЕС","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:16 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:35 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:12:58 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:12 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:13:17 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:13","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Switch","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor()","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"lazyById(250)","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":". It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"getIndexableAttributes()","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":") and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:40:06 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:40 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хм, интересна идея","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:03 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го проверя","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:17 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"така или иначе в понеделник ще иде на прод, днес не ми се рискува","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 6:05:10 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"мм, прав си","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:26 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:35 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor не зарежда допълннителните таблици","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:07 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:16 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"което обезмисля цялата гимнастика","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:21 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го ревизирам с lazy loading","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:43 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4002048453915948991
|
-1284830094648227768
|
idle
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:35 PM
6:05
cursor не зарежда допълннителните таблици
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:07 PM
6:06
ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:16 PM
6:06
което обезмисля цялата гимнастика
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:21 PM
6:06
ще го ревизирам с lazy loading
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:43 PM
6:06
на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
PhostorimcodeFV faVsco.js?9 JY-20725-handle-HS-search-rate-limiProledey(© RemoteCrmobjectmanif © HubspotSyncStrategybase.png€ ResponseNormalize.pheCachedcrmservicebecorator.onpsyncrielaAction.ong© SyncRelatedActivityMar© MatchActivityCrmData.php© CrmActivityService.phgc) MatchermDatc wednooksynebalchrrov O IntegrationAppdosearchx 5 Cc WTIY:>D Accessors>© Api• contiaO DTOW) FiltersM.lobsclass service excenas baseservice znpcemencs903904 CpubLic tunccion matchbybomaln Scring saomain, tinc suseria = nulu: tarrayProspectSearchStrateg)ServiceTraitsC) DataClient.oho© DecorateActivity.php© LocalSearch.phpelocalSearchinterface.of© RemoteSearch.php(C) Service.phpv Ml isteners913© ConvertLeadActivities.p© PurgeLookupCache.php> D MetadataD Migration[ Pipedrive915917>C FieldsC OpportunityMatcher> @ OpportunitySyncStrated921›_ Prospectsearchstrateay>W ServiceTraits925(c) Client.phpc) [EMAIL]) FieldDefinitions.onvC) PavloadBuilder.ohv929930(C) Profile, ohoC) @uervBuilder.ohoC) @uerv.andler.ohoC) @uerviterator nhol9331934(C) @uervRecults.nhn© Service.php(C) SvncRatchRedicServicescompanyname = soomarn'Try to find a company matchina their emall domain.ScompanyProperties = ['hs avatar filemanader key!.try 1ShsAccounts = Sthis->clientl->getInstance->comnaniesol->ceanchRvlomain(ScomnanvName ScomnanvPronenties)•} catch (Throwable $e) {Sthis->logger->info('[HubSpot] Search failed', ['error' => $e->getMessage()D):return nulbSaccount = null:I/ If there are multiple accounts. don'+ quess.we'll ask laterif count(ShsAccounts->data->results) zz= 10 <Persist this remote obiect.Saccount = Sthis->svncAccountShsAccounts->data->results101->comoanv1d0•M Traite© BaseClient.php© BaseService.php(C CachodGrm CorvicaDacoratSdata = Sthis->conventcrmlatald contact: nuil Saccount Susentd)•© CountryCodeResolver.php4) CrmActivitvProviderintegraneturn I emntvlannav filten(Sdata)) ? Sdata • null-rilo May 20:04.0g© ProspectCache.phpB7B48 MMSSATATl HI=custom.log ^4 SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console [PKou.# console leu)# console [slAGiNg)[2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"neaders".?"Uace":L"Inu,or May 2020 14.21.15 6Ml"Jn"Transter-Encod1nq":"chunked")."Connection":"keep-alive""CF-Ray" : ["9f80deb8db60dc3a-SOF"],"Strict-Transport-Secur1ty":"max-aqe=31536008* 1ncLudeSubDomains: preload")nacceot-encodino""server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\","x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"So+-Cookie"." c+hm-Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtmoV-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To".f"*"endpoints\":[{"unl".httns:la.nel.cloudflane.com./nenon+W/v42c=NVA1cVTPQfVm32anS0#xVF/sd2RN\"group\":\"cf-nel\","max_age\":604800}"]|"NEL": ["1success_traccion.0.01rreportto. "cr-nel,"max age":604800}"]"Server": ["cloudflare"]}} {"correlation_1d":"95256555-ec78-4541-b9za-adta/Sb6Yeab"."trace_10":C/AD8565-905t-4604-9405-0e5b551e5545CascadeHubspot Rate LimitindAskJiminnyReportActivityServiceTest -Hubspot Rate Limit ReInvestigating Rate LinNew CascadeHubspot CRM Call Re- 11I1Actions/SyncArchivedProfilesAction.phpCallVia executeRequest()?Rate Limitapp/Services/Activity/HubSpot/Service.phpThis service uses Sthis=›crmService (the CRM Service.oho))- it makes no direct HubSpot APl calls itselt. All calls delegate through crmservice-›aetcal10, crmService->searchCallsForPeriod(), crmService->syncOpportunity(), crmService->parseRecords() .Critical Findings1. Line 1313 - raw searchApi→>doSearch - matchExactlyByParticipantinService.pno:#Service.oho:1313)Sresponse = sthis->cuient->aetNewinstance->crmo->contactso-searchAoi->doSearchSoavload):• Goes completely around the Client wrapper - no 429 handling, no RateLimitException, no rate limit awareness•Uses the search rate limit bucket• Can be replaced with $this->client-›search('contacts', $payload) - same endpoint, same result, adds 429 protection,tine 020.022-comnandoctl.sconrchRuhorninfl_matchRuDomain/).• Service.php:920-923ShsAccounts = $this->client->getInstance()->companies()->searchByDomain(ScompanyName, ScompanyProperties):• Uses v1 SDK's searchByDomain which calls a search endpoint — hits the search rate limit bucket• No 429 protection• Cannot be trivially replaced with client-›search() (different endpoint/format), but could be wrapped in executeRequest ()2.detdnnortunitvRvldhac executeReauestcommented out.• Client.php:238-239$deal = Sthis->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(• Deliberatelv disabled _ this means sinale deal fetches in HubsootSingleSvncStrateav also aet no 429 protection.Ask anvthina (&4L)Tnl "896-20UITE.Río 4 spaces...
|
10153
|
NULL
|
NULL
|
NULL
|
|
10156
|
465
|
0
|
2026-05-08T17:04:49.843125+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778259889843_m1.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 3 new items - S Vasil Vasilev (DM) - Jiminny Inc - 3 new items - Slack...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:35 PM
6:05
cursor не зарежда допълннителните таблици
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:07 PM
6:06
ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:16 PM
6:06
което обезмисля цялата гимнастика
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:21 PM
6:06
ще го ревизирам с lazy loading
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:43 PM
6:06
на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.51180553,"top":0.08111111,"width":0.025,"height":0.04},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"bounds":{"left":0.50625,"top":0.14,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.5138889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.50625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"bounds":{"left":0.5159722,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.50625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.51111114,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51111114,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.5159722,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.50625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"bounds":{"left":0.51666665,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51666665,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.5208333,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.50625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"bounds":{"left":0.5152778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.50625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"bounds":{"left":0.5152778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.68472224,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.072222225,"height":0.011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.58819443,"top":0.15,"width":0.057638887,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.15,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.59305555,"top":0.15,"width":0.05277778,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.58819443,"top":0.18111111,"width":0.054166667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.58819443,"top":0.21222222,"width":0.034027778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.58819443,"top":0.24333334,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.58819443,"top":0.27444443,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.27444443,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.59444445,"top":0.27444443,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.58819443,"top":0.30555555,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.58819443,"top":0.33666667,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.58819443,"top":0.36777776,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.58819443,"top":0.3988889,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.3988889,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.59305555,"top":0.3988889,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.58819443,"top":0.43,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.58819443,"top":0.4611111,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.58819443,"top":0.49222222,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.49222222,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.5923611,"top":0.49222222,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.58819443,"top":0.5655556,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.5655556,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.59444445,"top":0.5655556,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.58819443,"top":0.5966667,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.58819443,"top":0.62777776,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.58819443,"top":0.6588889,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.6666667,"top":0.6588889,"width":0.013194445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.6715278,"top":0.6588889,"width":0.029861111,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.6715278,"top":0.6588889,"width":0.008333334,"height":0.02}},{"char_start":1,"char_count":13,"bounds":{"left":0.6798611,"top":0.6588889,"width":0.060416665,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.58819443,"top":0.69,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.58819443,"top":0.7211111,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":23,"bounds":{"left":0.58819443,"top":0.75222224,"width":0.016666668,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.58819443,"top":0.78333336,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.58819443,"top":0.8144444,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.58819443,"top":0.84555554,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.65555555,"top":0.84555554,"width":0.013194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.65555555,"top":0.84555554,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":2,"bounds":{"left":0.66041666,"top":0.84555554,"width":0.011805556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":24,"bounds":{"left":0.58819443,"top":0.91888887,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.58819443,"top":0.95,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.71319443,"top":0.12777779,"width":0.06458333,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"bounds":{"left":0.7326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.7798611,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.79930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.85347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"bounds":{"left":0.87291664,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.87291664,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.8784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXRadioButton","text":"Pins","depth":17,"bounds":{"left":0.9,"top":0.12777779,"width":0.04236111,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pins","depth":19,"bounds":{"left":0.91944444,"top":0.14,"width":0.017361112,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.9444444,"top":0.12777779,"width":0.022916667,"height":0.04222222},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.8229167,"top":0.17666666,"width":0.05277778,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:43 PM","depth":23,"bounds":{"left":0.8090278,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52 PM","depth":24,"bounds":{"left":0.8090278,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, привет","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.07083333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:48 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хвърли моля те едно око тука","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.14444445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:49 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/app/pull/12059","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/app/pull/12059","depth":25,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:53:03 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:53","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"опитвам се да оптимизирам процеса по индексиране на активитита за ЕС","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.19305556,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:16 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.22638889,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:54:35 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.22430556,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8111111,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:12:58 PM","depth":23,"bounds":{"left":0.81666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:12 PM","depth":24,"bounds":{"left":0.81666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.23194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:13:17 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:13","depth":25,"bounds":{"left":0.72430557,"top":0.16222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Switch","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.033333335,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor()","depth":25,"bounds":{"left":0.7826389,"top":0.16222222,"width":0.04027778,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to","depth":24,"bounds":{"left":0.82569444,"top":0.16111112,"width":0.015277778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"lazyById(250)","depth":25,"bounds":{"left":0.84305555,"top":0.16222222,"width":0.06527778,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":". It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.22291666,"height":0.09111111},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.9111111,"top":0.15888889,"width":0.0027777778,"height":0.02}},{"char_start":1,"char_count":132,"bounds":{"left":0.7465278,"top":0.15888889,"width":0.22291666,"height":0.093333334}}],"role_description":"text"},{"role":"AXStaticText","text":"getIndexableAttributes()","depth":25,"bounds":{"left":0.74930555,"top":0.26,"width":0.12013889,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":") and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).","depth":24,"bounds":{"left":0.7465278,"top":0.25666666,"width":0.22638889,"height":0.06888889},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.87222224,"top":0.25666666,"width":0.0027777778,"height":0.02}},{"char_start":1,"char_count":108,"bounds":{"left":0.7465278,"top":0.25666666,"width":0.22638889,"height":0.06888889}}],"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.33666667,"width":0.057638887,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.33888888,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:40:06 PM","depth":23,"bounds":{"left":0.8090278,"top":0.3422222,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:40 PM","depth":24,"bounds":{"left":0.8090278,"top":0.3422222,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хм, интересна идея","depth":24,"bounds":{"left":0.7465278,"top":0.36333334,"width":0.093055554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.31777778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:03 PM","depth":24,"bounds":{"left":0.72430557,"top":0.4,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"bounds":{"left":0.72430557,"top":0.4,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го проверя","depth":24,"bounds":{"left":0.7465278,"top":0.39666668,"width":0.06944445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.36222222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:17 PM","depth":24,"bounds":{"left":0.72430557,"top":0.43333334,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"bounds":{"left":0.72430557,"top":0.43333334,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"така или иначе в понеделник ще иде на прод, днес не ми се рискува","depth":24,"bounds":{"left":0.7465278,"top":0.43,"width":0.22152779,"height":0.044444446},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.43,"width":0.0055555557,"height":0.02}},{"char_start":1,"char_count":64,"bounds":{"left":0.7465278,"top":0.43,"width":0.22152779,"height":0.044444446}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.39555556,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.48555556,"width":0.057638887,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.48777777,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 6:05:10 PM","depth":23,"bounds":{"left":0.8090278,"top":0.4911111,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05 PM","depth":24,"bounds":{"left":0.8090278,"top":0.4911111,"width":0.031944446,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"мм, прав си","depth":24,"bounds":{"left":0.7465278,"top":0.51222223,"width":0.055555556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.46666667,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:26 PM","depth":24,"bounds":{"left":0.72430557,"top":0.54888886,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"bounds":{"left":0.72430557,"top":0.54888886,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем","depth":24,"bounds":{"left":0.7465278,"top":0.54555553,"width":0.22291666,"height":0.044444446},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.54555553,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":71,"bounds":{"left":0.7465278,"top":0.54555553,"width":0.22222222,"height":0.044444446}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.51111114,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:05:35 PM","depth":24,"bounds":{"left":0.72430557,"top":0.6066667,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:05","depth":25,"bounds":{"left":0.72430557,"top":0.6066667,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor не зарежда допълннителните таблици","depth":24,"bounds":{"left":0.7465278,"top":0.60333335,"width":0.21944444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.5688889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.5688889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.5688889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.5688889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:07 PM","depth":24,"bounds":{"left":0.72430557,"top":0.64,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"bounds":{"left":0.72430557,"top":0.64,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало","depth":24,"bounds":{"left":0.7465278,"top":0.63666666,"width":0.23472223,"height":0.06888889},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.63666666,"width":0.009027778,"height":0.02}},{"char_start":1,"char_count":107,"bounds":{"left":0.7465278,"top":0.63666666,"width":0.23472223,"height":0.06888889}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.6022222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.6022222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.6022222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.6022222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:16 PM","depth":24,"bounds":{"left":0.72430557,"top":0.7222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"bounds":{"left":0.72430557,"top":0.7222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"което обезмисля цялата гимнастика","depth":24,"bounds":{"left":0.7465278,"top":0.7188889,"width":0.17569445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.6844444,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.6844444,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.6844444,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.6844444,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:21 PM","depth":24,"bounds":{"left":0.72430557,"top":0.75555557,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"bounds":{"left":0.72430557,"top":0.75555557,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го ревизирам с lazy loading","depth":24,"bounds":{"left":0.7465278,"top":0.75222224,"width":0.14513889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.7177778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.7177778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.7177778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.7177778,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 6:06:43 PM","depth":24,"bounds":{"left":0.72430557,"top":0.7888889,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:06","depth":25,"bounds":{"left":0.72430557,"top":0.7888889,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти","depth":24,"bounds":{"left":0.7465278,"top":0.78555554,"width":0.23194444,"height":0.06888889},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.78555554,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":90,"bounds":{"left":0.7465278,"top":0.78555554,"width":0.23194444,"height":0.06888889}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.7511111,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.7511111,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.7511111,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.7511111,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"bounds":{"left":0.71666664,"top":0.88,"width":0.26527777,"height":0.04222222},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4002048453915948991
|
-1284830094648227768
|
idle
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 6:05:10 PM
6:05 PM
мм, прав си
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:26 PM
6:05
задълбах по на дълбоко, и се оказва, че cursor ще произведе друг проблем
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:05:35 PM
6:05
cursor не зарежда допълннителните таблици
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:07 PM
6:06
ще стриймне моделите, но за всеки ще вика поотделно with(opportunities, leads, accounts….) и всичко останало
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:16 PM
6:06
което обезмисля цялата гимнастика
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:21 PM
6:06
ще го ревизирам с lazy loading
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 6:06:43 PM
6:06
на по малки бачове, за да спестя памет от моделите, просто ще взема данните на няколко пъти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
SlackFileEditViewGoHistoryWindowHelpLukás Koválik's No...ProGPHubspot API calls+n Home1000TestDailyAgents+ New agentWorkspace* Quick NoteWorkJira ticketView of SprintDailyPlanSprint|Stefka 1-1|TododevEvaluationKnowledgee IdeasPrivateE Home viewsIntegration-appWork KnowledgeWork Knowledgetesting keyboard4 Todo2 New chat x03 Hubspot / Hubspot API callsCritical Findings1. Line 1313 - rawsearchApi()->doSearch()- matchEx|Sresponse = $this->client->getNewInstance()->crm(• Goes completely around the Client wrapper - no 429• Uses the search rate limit bucket• Can be replaced with $this->client->search('contacts"2. Line 920-923 — companies()->searchByDomain() - m$hsAccounts = $this->client->getInstance()->compai• Uses v1 SDK's searchByDomainwhich calls a search e• No 429 protection• Cannot be trivially replaced with client->search() (diffePress 'space' for Al or 'l' for commands40QHomeDMsActivityFilesLater...MoreED→Jiminny... v# conrusion-cHnic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Direct messagesSo Vasil Vasilevao Nikolay IvanovGalya DimitrovaAneliya Angelova, ...2 Stoyan Tanev €ã. Stefka StoyanovaC. Ves. Aneliya Angelovado James GrahamLukas Kovalik y... O::: AppsToalJira Cloudlabl100% <•Fri 8 May 20:04:55Describe what you are looking forVasil Vasilev• MessagesAdd canvasO Files< Pins+carsoro to LazyDyia(coueipreseivesthe single-loop, gToday~-yle code in the newversion while restoring proper batched eagerloading (avoiding N+1 ongetIndexableAttributes ) and releasing the DBconnection between chunks (avoiding long-heldPDO connections during ES/Sentry calls).Vasil Vasilev 4:40 PMхм, интересна идеяще го проверятака или иначе в понеделник ще иде на прод.днес не ми се рискуваVasil Vasilev 6:05 PMмм, прав сизадълбах по на дълбоко, и се оказва, че cursorще произведе друг проблемcursor не зарежда допьлннителните таблицище стриймне моделите, но за всеки ще викапоотделно with(opportunities, leads, accounts....) ивсичко останалокоето обезмисля цялата гимнастикаще го ревизирам с lazy loadingна по малки бачове, за да спестя памет отмоделите, просто ще взема данните на няколкопЪтиMessage Vasil Vasilev+...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10154
|
NULL
|
0
|
2026-05-08T14:26:41.311234+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778250401311_m1.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 3 new items - S Vasil Vasilev (DM) - Jiminny Inc - 3 new items - Slack...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Apr 28th at 4:51:31 PM
4:51 PM
a, ти искаш в amazon да добавим ключ за достъп до QAi ?
Apr 28th at 4:51:38 PM
4:51
Вес се грижи за тея неща
Apr 28th at 4:52:06 PM
4:52
дори не съм сигурен дали тоя ключ не трябва да бъде в CircleCI при билда на имиджа
Apr 28th at 4:52:10 PM
4:52
т.е.
Apr 28th at 4:52:12 PM
4:52
пак не знам
Lukas Kovalik
Apr 28th at 4:53:41 PM
4:53 PM
ок, ще питам Вес, мерси
Vasil Vasilev
Apr 28th at 5:00:16 PM
5:00 PM
моля
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
React with white_check_mark
React with eyes...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.51180553,"top":0.08111111,"width":0.025,"height":0.04},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"bounds":{"left":0.50625,"top":0.14,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.5138889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.50625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"bounds":{"left":0.5159722,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.50625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.51111114,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51111114,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.5159722,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.50625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"bounds":{"left":0.51666665,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51666665,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.5208333,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.50625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"bounds":{"left":0.5152778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.50625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"bounds":{"left":0.5152778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.68472224,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.57708335,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.58819443,"top":0.12777779,"width":0.072222225,"height":0.011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.58819443,"top":0.15,"width":0.057638887,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.15,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.59305555,"top":0.15,"width":0.05277778,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.58819443,"top":0.18111111,"width":0.054166667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.58819443,"top":0.21222222,"width":0.034027778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.58819443,"top":0.24333334,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.58819443,"top":0.27444443,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.27444443,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.59444445,"top":0.27444443,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.58819443,"top":0.30555555,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.58819443,"top":0.33666667,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.58819443,"top":0.36777776,"width":0.038194444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.58819443,"top":0.3988889,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.3988889,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.59305555,"top":0.3988889,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.58819443,"top":0.43,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.58819443,"top":0.4611111,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.58819443,"top":0.49222222,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.49222222,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.5923611,"top":0.49222222,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.58819443,"top":0.5655556,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.58819443,"top":0.5655556,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.59444445,"top":0.5655556,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.58819443,"top":0.5966667,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.58819443,"top":0.62777776,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.58819443,"top":0.6588889,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.6666667,"top":0.6588889,"width":0.013194445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.6715278,"top":0.6588889,"width":0.029861111,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.6715278,"top":0.6588889,"width":0.008333334,"height":0.02}},{"char_start":1,"char_count":13,"bounds":{"left":0.6798611,"top":0.6588889,"width":0.060416665,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.58819443,"top":0.69,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.58819443,"top":0.7211111,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":23,"bounds":{"left":0.58819443,"top":0.75222224,"width":0.016666668,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.58819443,"top":0.78333336,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.58819443,"top":0.8144444,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.58819443,"top":0.84555554,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.65555555,"top":0.84555554,"width":0.013194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.65555555,"top":0.84555554,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":2,"bounds":{"left":0.66041666,"top":0.84555554,"width":0.011805556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":24,"bounds":{"left":0.58819443,"top":0.91888887,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.58819443,"top":0.95,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.71319443,"top":0.12777779,"width":0.06458333,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"bounds":{"left":0.7326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.7798611,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.79930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.85347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"bounds":{"left":0.87291664,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.87291664,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.8784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXRadioButton","text":"Pins","depth":17,"bounds":{"left":0.9,"top":0.12777779,"width":0.04236111,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pins","depth":19,"bounds":{"left":0.91944444,"top":0.14,"width":0.017361112,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.9444444,"top":0.12777779,"width":0.022916667,"height":0.04222222},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.7965278,"top":0.16111112,"width":0.10555556,"height":0.0011111111},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 4:51:31 PM","depth":23,"bounds":{"left":0.8090278,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:51 PM","depth":24,"bounds":{"left":0.8090278,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"a, ти искаш в amazon да добавим ключ за достъп до QAi ?","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.19930555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 4:51:38 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:51","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Вес се грижи за тея неща","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.12291667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 4:52:06 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:52","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"дори не съм сигурен дали тоя ключ не трябва да бъде в CircleCI при билда на имиджа","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.2361111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 4:52:10 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:52","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"т.е.","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.015277778,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 4:52:12 PM","depth":24,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:52","depth":25,"bounds":{"left":0.72430557,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"пак не знам","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.059027776,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8111111,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 4:53:41 PM","depth":23,"bounds":{"left":0.81666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:53 PM","depth":24,"bounds":{"left":0.81666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ок, ще питам Вес, мерси","depth":24,"bounds":{"left":0.76180553,"top":0.16111112,"width":0.12083333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:00:16 PM","depth":23,"bounds":{"left":0.8090278,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:00 PM","depth":24,"bounds":{"left":0.8090278,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"моля","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.025,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.8229167,"top":0.17666666,"width":0.05277778,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.8041667,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:43 PM","depth":23,"bounds":{"left":0.8090278,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52 PM","depth":24,"bounds":{"left":0.8090278,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, привет","depth":24,"bounds":{"left":0.7465278,"top":0.16111112,"width":0.07083333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:48 PM","depth":24,"bounds":{"left":0.72430557,"top":0.19555555,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.72430557,"top":0.19555555,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хвърли моля те едно око тука","depth":24,"bounds":{"left":0.7465278,"top":0.19222222,"width":0.14444445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.16111112,"width":0.022222223,"height":0.032222223},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.16111112,"width":0.022222223,"height":0.032222223},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.16111112,"width":0.022222223,"height":0.032222223},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.16111112,"width":0.022222223,"height":0.032222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:52:49 PM","depth":24,"bounds":{"left":0.72430557,"top":0.22888888,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.72430557,"top":0.22888888,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/app/pull/12059","depth":24,"bounds":{"left":0.7465278,"top":0.22555555,"width":0.19791667,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/app/pull/12059","depth":25,"bounds":{"left":0.7465278,"top":0.22555555,"width":0.19791667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.19111112,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.19111112,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.19111112,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.19111112,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:53:03 PM","depth":24,"bounds":{"left":0.72430557,"top":0.26222223,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:53","depth":25,"bounds":{"left":0.72430557,"top":0.26222223,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"опитвам се да оптимизирам процеса по индексиране на активитита за ЕС","depth":24,"bounds":{"left":0.7465278,"top":0.2588889,"width":0.19305556,"height":0.044444446},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.2588889,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":67,"bounds":{"left":0.7465278,"top":0.2588889,"width":0.19305556,"height":0.044444446}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.22444445,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.22444445,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"bounds":{"left":0.84930557,"top":0.22444445,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"bounds":{"left":0.8715278,"top":0.22444445,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:54:16 PM","depth":24,"bounds":{"left":0.72430557,"top":0.32,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"bounds":{"left":0.72430557,"top":0.32,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита","depth":24,"bounds":{"left":0.7465278,"top":0.31666666,"width":0.22638889,"height":0.044444446},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7465278,"top":0.31666666,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":86,"bounds":{"left":0.7465278,"top":0.31666666,"width":0.22638889,"height":0.044444446}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8048611,"top":0.2822222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"bounds":{"left":0.82708335,"top":0.2822222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1611944469217501561
|
-8132271747783029722
|
idle
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Apr 28th at 4:51:31 PM
4:51 PM
a, ти искаш в amazon да добавим ключ за достъп до QAi ?
Apr 28th at 4:51:38 PM
4:51
Вес се грижи за тея неща
Apr 28th at 4:52:06 PM
4:52
дори не съм сигурен дали тоя ключ не трябва да бъде в CircleCI при билда на имиджа
Apr 28th at 4:52:10 PM
4:52
т.е.
Apr 28th at 4:52:12 PM
4:52
пак не знам
Lukas Kovalik
Apr 28th at 4:53:41 PM
4:53 PM
ок, ще питам Вес, мерси
Vasil Vasilev
Apr 28th at 5:00:16 PM
5:00 PM
моля
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
React with white_check_mark
React with eyes
SlackFileEditViewGoHistoryWindowHelpLukás Koválik's No...ProGPHubspot API calls+n Home1000TestDailyAgents+ New agentWorkspace* Quick NoteWorkJira ticketView of SprintDailyPlanSprintStefka 1-1TododevEvaluationKnowledgera IdeasPrivateE Home viewsIntegration-appWork KnowledgeWork Knowledgetesting keyboard4Todo2 New chat x03 Hubspot / Hubspot API callsCritical Findings1. Line 1313 - rawsearchApi()->doSearch()- matchExSresponse = Sthis->client->getNewInstance()->crm(• Goes completely around the Client wrapper - no 429• Uses the search rate limit bucket• Can be replaced with $this->client->search('contacts"2. Line 920-923 — companies()->searchByDomain() - m$hsAccounts = $this->client->getInstance()->compai• Uses v1 SDK's searchByDomainwhich calls a search e• No 429 protection• Cannot be trivially replaced with client->search() (diffePress 'space' for Al or 'l' for commands40QHomeDMsActivityFilesLater...MoreED→Jiminny... v# conrusion-clnic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Direct messagese. Vasil Vasilevo Nikolay IvanovGalya DimitrovaAneliya Angelova, ...2 Stoyan Tanev €ã. Stefka StoyanovaC Vese. Aneliya Angelovado James GrahamLukas Kovalik y... O::: AppsToalJira Cloud100% CFri 8 May 17:26:41Describe what you are looking forVasil Vasilev6 0MessagesAdd canvasлукаш, привет@ Files< Pins+Todayхвърли моля те смгукаhttps://github.com/jiminny/app/pull/12059опитвам се да оптимизирам процеса поиндексиране на активитита за ЕСидеята е да намаля паметта която се ползва зада се генерира един бач от 100 активититаи после да увелича размера на бачовете, за даимаме по малко blocking операции в ЕС, катореиндексираLukas Kovalik 4:12 PMздрасти, изглежда ок, но когато го минах и презgemini ми даде един warning.Switch cursor() to lazyById(250) . It preservesthe single-loop, generator-style code in the newversion while restoring proper batched eagerloading (avoiding N+1 ongetIndexableAttributes() ) and releasing the DBconnection between chunks (avoiding long-heldPDO connections during ES/Sentry calls).Vasil Vasilev 4:40 PMхм, интересна идеяще го проверятака или иначе в понеделник ще иде на прод,днес не ми се рискуваMessage Vasil Vasilev+Aa..•...
|
10152
|
NULL
|
NULL
|
NULL
|
|
10153
|
NULL
|
0
|
2026-05-08T14:26:40.779015+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778250400779_m2.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 3 new items - S Vasil Vasilev (DM) - Jiminny Inc - 3 new items - Slack...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Apr 28th at 4:51:31 PM
4:51 PM
a, ти искаш в amazon да добавим ключ за достъп до QAi ?
Apr 28th at 4:51:38 PM
4:51
Вес се грижи за тея неща
Apr 28th at 4:52:06 PM
4:52
дори не съм сигурен дали тоя ключ не трябва да бъде в CircleCI при билда на имиджа
Apr 28th at 4:52:10 PM
4:52
т.е.
Apr 28th at 4:52:12 PM
4:52
пак не знам
Lukas Kovalik
Apr 28th at 4:53:41 PM
4:53 PM
ок, ще питам Вес, мерси
Vasil Vasilev
Apr 28th at 5:00:16 PM
5:00 PM
моля
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
loading…...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.5152925,"top":1.0,"width":0.011968086,"height":-0.058260202},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.5980718,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.61170214,"top":1.0,"width":0.030917553,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.64361703,"top":1.0,"width":0.034242023,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.6788564,"top":1.0,"width":0.020944148,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Pins","depth":17,"bounds":{"left":0.70113033,"top":1.0,"width":0.020279255,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pins","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.7224069,"top":1.0,"width":0.010970744,"height":-0.09177971},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 4:51:31 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:51 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"a, ти искаш в amazon да добавим ключ за достъп до QAi ?","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 4:51:38 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:51","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Вес се грижи за тея неща","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 4:52:06 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:52","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"дори не съм сигурен дали тоя ключ не трябва да бъде в CircleCI при билда на имиджа","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 4:52:10 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:52","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"т.е.","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 4:52:12 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:52","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"пак не знам","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 4:53:41 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:53 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ок, ще питам Вес, мерси","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:00:16 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:00 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"моля","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:43 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, привет","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:52:48 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хвърли моля те едно око тука","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:52:49 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/app/pull/12059","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/app/pull/12059","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:53:03 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:53","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"опитвам се да оптимизирам процеса по индексиране на активитита за ЕС","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:54:16 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:54:35 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:54","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:12:58 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:12 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:13:17 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:13","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Switch","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"cursor()","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"lazyById(250)","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":". It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"getIndexableAttributes()","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":") and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:40:06 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:40 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хм, интересна идея","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:03 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ще го проверя","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:41:17 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:41","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"така или иначе в понеделник ще иде на прод, днес не ми се рискува","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"loading…","depth":11,"on_screen":false,"role_description":"text"}]...
|
4944844419085215203
|
-1280405623264868284
|
idle
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
James Graham
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Vasil Vasilev
Apr 28th at 4:51:31 PM
4:51 PM
a, ти искаш в amazon да добавим ключ за достъп до QAi ?
Apr 28th at 4:51:38 PM
4:51
Вес се грижи за тея неща
Apr 28th at 4:52:06 PM
4:52
дори не съм сигурен дали тоя ключ не трябва да бъде в CircleCI при билда на имиджа
Apr 28th at 4:52:10 PM
4:52
т.е.
Apr 28th at 4:52:12 PM
4:52
пак не знам
Lukas Kovalik
Apr 28th at 4:53:41 PM
4:53 PM
ок, ще питам Вес, мерси
Vasil Vasilev
Apr 28th at 5:00:16 PM
5:00 PM
моля
Jump to date
Vasil Vasilev
Today at 2:52:43 PM
2:52 PM
Лукаш, привет
Today at 2:52:48 PM
2:52
хвърли моля те едно око тука
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:49 PM
2:52
https://github.com/jiminny/app/pull/12059
https://github.com/jiminny/app/pull/12059
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:53:03 PM
2:53
опитвам се да оптимизирам процеса по индексиране на активитита за ЕС
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:54:16 PM
2:54
идеята е да намаля паметта която се ползва за да се генерира един бач от 100 активитита
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:54:35 PM
2:54
и после да увелича размера на бачовете, за да имаме по малко blocking операции в ЕС, като реиндексира
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 4:12:58 PM
4:12 PM
здрасти, изглежда ок, но когато го минах и през gemini ми даде един warning.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:13:17 PM
4:13
Switch
cursor()
to
lazyById(250)
. It preserves the single-loop, generator-style code in the new version while restoring proper batched eager loading (avoiding N+1 on
getIndexableAttributes()
) and releasing the DB connection between chunks (avoiding long-held PDO connections during ES/Sentry calls).
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Vasil Vasilev
Today at 4:40:06 PM
4:40 PM
хм, интересна идея
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:03 PM
4:41
ще го проверя
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:41:17 PM
4:41
така или иначе в понеделник ще иде на прод, днес не ми се рискува
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
loading…
PhostorimcodeFV faVsco.js?9 JY-20725-handle-HS-search-rate-limiProledey(© RemoteCrmobjectmanif © HubspotSyncStrategybase.png€ ResponseNormalize.phrCachedcrmservicebecorator.onp© syncrielaAction.ong© SyncRelatedActivityMar© MatchActivityCrmData.php© CrmActivityService.phgc) MatchermDatc wednooksynebalchrrov O IntegrationAppdosearchx 5 Cc wTIY:>D Accessors>© Api• contiaO DTOW) FiltersM.lobsclass service excenas baseservice znpcemencs903904 Cpubuic tunccion macchbybomaln scring saomain, tinc suserla = nulu: rarrayProspectSearchStrateg)ServiceTraitsC) DataClient.oho© DecorateActivity.php© LocalSearch.phpelocalSearchinterface.of© RemoteSearch.php(C) Service.phpv Ml isteners913© ConvertLeadActivities.p© PurgeLookupCache.php> D MetadataD Migration[ Pipedrive915917>C FieldsC OpportunityMatcher> @ OpportunitySyncStrated921›_ Prospectsearchstrateay>W ServiceTraits925(c) Client.phpc) [EMAIL]) FieldDefinitions.onvC) PavloadBuilder.ohv929930(C) Profile, ohoC) @uervBuilder.ohoC) @uerv.andler.ohoC) @uerviterator nhol9331934(C) @uervRecults.nhn© Service.php(C) SvncRatchRedicServicescompanyname = soomarn'Try to find a company matchina their emall domain.ScompanyProperties = ['hs avatar filemanader key!.try 1ShsAccounts = Sthis->clientl->getInstance->comnaniesol->ceanchRvlomain(ScomnanvName ScomnanvPronenties)•} catch (Throwable $e) {Sthis->logger->info('[HubSpot] Search failed', ['error' => $e->getMessage()D):return nulbSaccount = null:I/ If there are multiple accounts. don'+ quess.we'll ask laterif count(ShsAccounts->data->results) zz= 10 <Persist this remote obiect.Saccount = Sthis->svncAccount(ShsAccounts->data->results10l->comoanvid0•M Traite© BaseClient.php© BaseService.php(C CachodGrm CorvicaDacoratSdata = Sthis->conventcrmlatald contact: niin Saccount, Susentd).© CountryCodeResolver.php4) CrmActivitvProviderintegraneturn I emntvlannav filten(Sdata)) ? Sdata • null-ril o May 1/:20.40© ProspectCache.phpB7B48 MMSSATATl HI=custom.log ^4 SF (jiminny@localhost]4 HS_local [jiminny@localhost]# console [PKou.# console leu)# console [slAGiNg)[2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"neaders".?"Uace":L"Inu,or May 2020 14.21.15 6Ml"Jn"Transter-Encod1nq":"chunked")."Connection":"keep-alive""CF-Ray" : ["9f80deb8db60dc3a-SOF"],"Strict-Transport-Secur1ty":"max-aqe=31536008* 1ncLudeSubDomains: preload")nacceot-encodino""server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\","x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"So+-Cookie"." c+hm-Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtm0V-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To".f"*"endpoints\":[{"unl".httns:la.nel.cloudflane.com./nenon+W/v42c=NVA1cVTPQfVm32anS0#xVF/sd2RN\"group\":\"cf-nel\","max_age\":604800}"]|"NEL":["{success_traccion.0.01rreportto. "cr-nel,"max age":604800}"]"Server": ["cloudflare"]}} {"correlation_1d":"95256555-ec78-4541-b9za-adta/Sb6Yeab"."trace_10":C/AD8565-905t-4604-9405-0e5b551e5545CascadeHubspot Rate LimitindHubspot Rate Limit ReInvestigating Rate LinNew CascadeHubspot CRM Call ReActions/SyncArchivedProfilesAction.phpCallVia executeRequest()?Rate Limitapp/Services/Activity/HubSpot/Service.phpThis service uses Sthis=›crmService (the CRM Service.oho))- it makes no direct HubSpot APl calls itselt. All calls delegate through crmservice-›aetcal10, crmService->searchCallsForPeriod(), crmService->syncOpportunity(), crmService->parseRecords() .Critical Findings1. Line 1313 - raw searchApi→>doSearch - matchExactlyByParticipantinService.po:#Service.oho:1313)Sresponse = sthis->cuient->aetNewinstance->crmo->contactso-searchAoi->doSearchSoavload):• Goes comoletelv around the Client wraoper — no 429 handlina, no Ratel imitFxcention. no rate limit awareness•Uses the search rate limit bucket• Can be replaced with $this->client-›search('contacts', $payload) - same endpoint, same result, adds 429 protection,tine 020.022-comnandoctl.sconrchRuhorninfl_matchRuDomain/).• Service.php:920-923ShsAccounts = $this->client->getInstance()->companies()->searchByDomain(ScompanyName, ScompanyProperties):• Uses v1 SDK's searchByDomain which calls a search endooint — hits the search rate limit bucket• No 429 protection• Cannot be trivially replaced with client-›search() (different endpoint/format), but could be wrapped in executeRequest ()2.detdnnortunitvRvldhac executeReauestcommented out.• Client.php:238-239$deal = Sthis->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(• Deliberatelv disabled _ this means sinale deal fetches in HubsootSingleSvncStrateav also aet no 429 protection.Ask anvthina (&4L)Tnl "896-20UITE.Rfo 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|